<!DOCTYPE html>
<html lang="zh" dir="ltr">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>nuklear的设计与源码分析 – 邵晨峰的博客</title>
    


  
  <script defer src="/js/fuse.min.c4bee9a8d44273d6154fe86006923d4131eb2e8069d8897687137c6f37f553e3.js"></script>



<script src="/js/enquire.min.aa37bdcb743826eecdae5c5d177fc7d6552340f1b4378ffaa9c82b2c6111400b.js"></script>

<script defer src="/js/lazysizes.min.5e11d056075a05065b9c0bfec44084a113fc2976c2952ec804dedb61c7662db9.js"></script>

<script defer src="/js/helper/getParents.min.ccd45f158c1b17849307ba913a72beac239c410f2b6e648496a79842da84e55b.js"></script>

<script defer src="/js/helper/fadeinout.min.9fb19682560d5fa5596fffec85da605067c4acc86aad05add4d8fff9d362a446.js"></script>

<script>
  "use strict";
  
  
  var targetProtocol = "http:"; 
  if (window.location.protocol != targetProtocol)
    window.location.href = targetProtocol + window.location.href.substring(window.location.protocol.length);

  
  function baiduSearch(event) {
    var evt = window.event || event;
        if (evt.keyCode == 13) {
          console.log(event)
          var val = document.getElementById("search").value
          if(!val){
                  alert('搜索内容为空，请输入');
                  return false;
          }else{
            val = val + " site:shaochenfeng.com"
            window.open("https://www.baidu.com/s?ie=utf-8&wd=" + val);
          }
        }
  }

  window.onload = function() {
    
    var languagedir = JSON.parse("\"ltr\"");
    
    var baseurl = JSON.parse("\"http://shaochenfeng.com\"");
    
    var permalink = JSON.parse("\"http://shaochenfeng.com/blog/nuklear%E7%9A%84%E8%AE%BE%E8%AE%A1%E4%B8%8E%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/\"");

    
    var toggleSidebarElem = document.getElementById("toggle-sidebar");
    var toggleMenuElem = document.getElementById("toggle-menu");
    var tocBodyElem = document.querySelector('.toc__body');
    var tocLabelElem = document.querySelector('.toc__label');
    var listMainElem = document.getElementById('list-main');
    var listSideElem = document.getElementById('list-side');
    var singleMenuElem = document.getElementById('single-menu');
    var sliderIcons = document.querySelectorAll('.slider__icon');

    toggleSidebarElem ?
      toggleSidebarElem.addEventListener('change', function (e) {
        if (e.target.checked) {
          if (tocBodyElem) {
            fadeIn(tocBodyElem, 200);
          }
          if (tocLabelElem) {
            fadeIn(tocLabelElem, 200);
          }
          if (listMainElem && listSideElem) {
            listMainElem.className = 'm';
            listSideElem.className = 'r';
          }

          sliderIcons && sliderIcons.forEach(function (elem) {
            if (elem.classList.contains('hide')) {
              elem.classList.remove('hide');
            } else {
              elem.classList.add('hide');
            }
          });

        } else {
          if (tocBodyElem) {
            fadeOut(tocBodyElem, 200);
          }
          if (tocLabelElem) {
            fadeOut(tocLabelElem, 200);
          }
          if (listMainElem && listSideElem) {
            listMainElem.className = 'mr';
            listSideElem.className = 'hide';
          }

          sliderIcons && sliderIcons.forEach(function (elem) {
            if (elem.classList.contains('hide')) {
              elem.classList.remove('hide');
            } else {
              elem.classList.add('hide');
            }
          });
        }
      }) : null;

    toggleMenuElem ?
      toggleMenuElem.addEventListener('change', function (e) {
        if (e.target.checked) {
          if (listMainElem && singleMenuElem) {
            listMainElem.className = 'm';
            singleMenuElem.className = 'l';
          }

          sliderIcons && sliderIcons.forEach(function (elem) {
            if (elem.classList.contains('hide')) {
              elem.classList.remove('hide');
            } else {
              elem.classList.add('hide');
            }
          });

        } else {
          if (listMainElem && singleMenuElem) {
            listMainElem.className = 'lm';
            singleMenuElem.className = 'hide';
          }

          sliderIcons && sliderIcons.forEach(function (elem) {
            if (elem.classList.contains('hide')) {
              elem.classList.remove('hide');
            } else {
              elem.classList.add('hide');
            }
          });
        }
      }) : null;
    


    
    var navCollapseBtn = document.getElementById('navCollapseBtn');
    navCollapseBtn ? navCollapseBtn.addEventListener('click', function(e) {
      var navCollapse = document.querySelector('.navbar__collapse');
      
      if (navCollapse) {
        var dataOpen = navCollapse.getAttribute('data-open');

        if (dataOpen === 'true') {
          navCollapse.setAttribute('data-open', 'false');
          navCollapse.style.maxHeight = 0;
        } else {
          navCollapse.setAttribute('data-open', 'true');
          navCollapse.style.maxHeight = navCollapse.scrollHeight + "px";
        }
      }
    }) : null;
    


    
    var expandBtn = document.querySelectorAll('.expand__button');

    for (let i = 0; i < expandBtn.length; i++) {
      expandBtn[i].addEventListener("click", function () {
        var content = this.nextElementSibling;
        if (content.style.maxHeight) {
          content.style.maxHeight = null;
          this.querySelector('svg').classList.add('expand-icon__right');
          this.querySelector('svg').classList.remove('expand-icon__down');
        } else {
          content.style.maxHeight = content.scrollHeight + "px";
          this.querySelector('svg').classList.remove('expand-icon__right');
          this.querySelector('svg').classList.add('expand-icon__down');
        }
      });
    }
    



    
    document.querySelectorAll('.tab') ? 
    document.querySelectorAll('.tab').forEach(function(elem, idx) {
      var containerId = elem.getAttribute('id');
      var containerElem = elem;
      var tabLinks = elem.querySelectorAll('.tab__link');
      var tabContents = elem.querySelectorAll('.tab__content');
      var ids = [];

      tabLinks && tabLinks.length > 0 ?
      tabLinks.forEach(function(link, index, self) {
        link.onclick = function(e) {
          for (var i = 0; i < self.length; i++) {
            if (index === parseInt(i, 10)) {
              if (!self[i].classList.contains('active')) {
                self[i].classList.add('active');
                tabContents[i].style.display = 'block';
              }
            } else {
              self[i].classList.remove('active');
              tabContents[i].style.display = 'none';
            }
          }
        }
      }) : null;
    }) : null;
    


    
    document.querySelectorAll('.codetab') ? 
    document.querySelectorAll('.codetab').forEach(function(elem, idx) {
      var containerId = elem.getAttribute('id');
      var containerElem = elem;
      var codetabLinks = elem.querySelectorAll('.codetab__link');
      var codetabContents = elem.querySelectorAll('.codetab__content');
      var ids = [];

      codetabLinks && codetabLinks.length > 0 ?
      codetabLinks.forEach(function(link, index, self) {
        link.onclick = function(e) {
          for (var i = 0; i < self.length; i++) {
            if (index === parseInt(i, 10)) {
              if (!self[i].classList.contains('active')) {
                self[i].classList.add('active');
                codetabContents[i].style.display = 'block';
              }
            } else {
              self[i].classList.remove('active');
              codetabContents[i].style.display = 'none';
            }
          }
        }
      }) : null;
    }) : null;
    

    
    
    
    var enableDarkMode = JSON.parse("true");
    var root = document.getElementById('root');
    var toggleToLightBtn = document.getElementById('toggleToLight');
    var toggleToDarkBtn = document.getElementById('toggleToDark');

    if (!enableDarkMode) {
      root.className = 'theme__light';
      localStorage.setItem('theme', 'light');
    }
    
    if (toggleToDarkBtn) {
      toggleToDarkBtn.onclick = function (e) {
        root.className = 'theme__dark';
        localStorage.setItem('theme', 'dark');
        toggleToLightBtn.className = 'navbar__icons--icon';
        toggleToDarkBtn.className = 'hide';
      }
    }

    if (toggleToLightBtn) {
      toggleToLightBtn.onclick = function (e) {
        root.className = 'theme__light';
        localStorage.setItem('theme', 'light');
        toggleToLightBtn.className = 'hide';
        toggleToDarkBtn.className = 'navbar__icons--icon';
      }
    }

    
    document.querySelectorAll('.menu__list').forEach(function(elem) {
      if (elem.classList.contains('active')) {
        elem.style.maxHeight = elem.scrollHeight + "px"; 
      }
    });
    
    document.querySelectorAll('.menu__title--collapse').forEach(function(elem) {
      elem.addEventListener('click', function (e) {
        var content = this.nextElementSibling;
        var menuTitleIcon = this.querySelector('.menu__title--icon');
        if (!content) {
          return null;
        }

        var parent = elem.parentNode;
        while (parent.classList.contains('menu__list') && parent.classList.contains('active')) {
          parent.style.maxHeight = 100 * parent.children.length + "px";
          parent = parent.parentNode;
        }

        if (content.style.maxHeight) {
          content.style.maxHeight = null;
          content.classList.remove('active');
          menuTitleIcon.classList.add('right');
          
          if (languagedir === 'rtl') {
            menuTitleIcon.classList.remove('downrtl');
          } else {
            menuTitleIcon.classList.remove('down');
          }
        } else {
          content.style.maxHeight = content.scrollHeight + "px";
          content.classList.add('active');
          menuTitleIcon.classList.remove('right');
          
          if (languagedir === 'rtl') {
            menuTitleIcon.classList.add('downrtl');
          } else {
            menuTitleIcon.classList.add('down');
          }
        }
      });
    });
    


    
    var mobileLogo = document.getElementById('mobileLogo');
    var modal = document.getElementById("myModal");
    var drawer = document.getElementById('myDrawer');
    var drawerCloseBtn = document.querySelector('.drawer__close');

    var openDrawer = function() {
      modal.style.opacity = 1;

      if (languagedir === 'rtl') {
        modal.style.right = 0;
        drawer.style.right = 0;
      } else {
        modal.style.left = 0;
        drawer.style.left = 0;
      }
    }

    var closeDrawer = function() {
      modal.style.opacity = 0;

      if (languagedir === 'rtl') {
        drawer.style.right = '-100%';
      } else {
        drawer.style.left = '-100%';
      }

      
      setTimeout(function () {
        if (languagedir === 'rtl') {
          modal.style.right = '-100%';
        } else {
          modal.style.left = '-100%';
        }
      }, 250);
    }

    mobileLogo.onclick = function () {
      openDrawer();
      localStorage.setItem('isDrawerOpen', 'true');
    }

    modal.onclick = function () {
      closeDrawer();
      localStorage.setItem('isDrawerOpen', 'false');
    }

    drawerCloseBtn.onclick = function () {
      closeDrawer();
      localStorage.setItem('isDrawerOpen', 'false');
    }
  


  
    var lastScrollTop = window.pageYOffset || document.documentElement.scrollTop;
    var tocElem = document.querySelector('.toc');
    var tableOfContentsElem = tocElem ? tocElem.querySelector('#TableOfContents') : null;
    var singleContentsElem = document.querySelector('.single__contents');
    var dataBGImgs = document.querySelectorAll('div[data-bgimg]');

    
    var tocLevels = JSON.parse("null");

    if (tocLevels) {
      tocLevels = tocLevels.toString();
    } else {
      tocLevels = "h1, h2, h3, h4, h5, h6";
    }

    
    var isLandingBgImg = JSON.parse("null");
    
    var isHome = JSON.parse("false");

    function setNavbarBG(scrollTop) {
      if (isHome && isLandingBgImg && Object.keys(isLandingBgImg).length) {
        if (isLandingBgImg.height <= scrollTop) {
          dataBGImgs.forEach(function(elem) {
            elem.setAttribute('data-bgimg', 'false');
          });
        } else {
          dataBGImgs.forEach(function (elem) {
            elem.setAttribute('data-bgimg', 'true');
          });
        }
      }
    }
    setNavbarBG(lastScrollTop);

    window.onscroll = function () {
      var st = window.pageYOffset || document.documentElement.scrollTop;
      if (st > lastScrollTop) { 
        singleContentsElem ? 
        singleContentsElem.querySelectorAll(tocLevels.toString()).forEach(function(elem) {
          if (document.documentElement.scrollTop >= elem.offsetTop) {
            if (tableOfContentsElem) {
              var id = elem.getAttribute('id');
              tocElem.querySelectorAll('a').forEach(function (elem) {
                elem.classList.remove('active');
              });
              tocElem.querySelector('a[href="#' + id + '"]') ? 
              tocElem.querySelector('a[href="#' + id + '"]').classList.add('active') : null;
            }
          }
        }) : null;
        setNavbarBG(st);
      } else { 
        singleContentsElem ? 
        singleContentsElem.querySelectorAll(tocLevels.toString()).forEach(function(elem) {
          if (document.documentElement.scrollTop >= elem.offsetTop) {
            if (tableOfContentsElem) {
              var id = elem.getAttribute('id');
              tocElem.querySelectorAll('a').forEach(function (elem) {
                elem.classList.remove('active');
              });
              tocElem.querySelector('a[href="#' + id + '"]') ? 
              tocElem.querySelector('a[href="#' + id + '"]').classList.add('active') : null;
            }
          }
        }) : null;
        setNavbarBG(st);
      }
      lastScrollTop = st <= 0 ? 0 : st;
    };
    



    
    var mobileSearchInputElem = document.querySelector('#search-mobile');
    var mobileSearchClassElem = document.querySelector('.mobile-search');
    var mobileSearchBtnElem = document.querySelector('#mobileSearchBtn');
    var mobileSearchCloseBtnElem = document.querySelector('#search-mobile-close');
    var mobileSearchContainer = document.querySelector('#search-mobile-container');
    var mobileSearchResultsElem = document.querySelector('#search-mobile-results');
    var htmlElem = document.querySelector('html');

    if (mobileSearchClassElem) {
      mobileSearchClassElem.style.display = 'none';
    }

    mobileSearchBtnElem ? 
    mobileSearchBtnElem.addEventListener('click', function () {
      if (mobileSearchContainer) {
        mobileSearchContainer.style.display = 'block';
      }

      if (mobileSearchInputElem) {
        mobileSearchInputElem.focus();
      }

      if (htmlElem) {
        htmlElem.style.overflowY = 'hidden';
      }
    }) : null;

    mobileSearchCloseBtnElem ? 
    mobileSearchCloseBtnElem.addEventListener('click', function() {
      if (mobileSearchContainer) {
        mobileSearchContainer.style.display = 'none';
      }

      if (mobileSearchInputElem) {
        mobileSearchInputElem.value = '';
      }
      
      if (mobileSearchResultsElem) {
        while (mobileSearchResultsElem.firstChild) {
          mobileSearchResultsElem.removeChild(mobileSearchResultsElem.firstChild);
        }
      }

      if (htmlElem) {
        htmlElem.style.overflowY = 'visible';
      }
    }) : null;

    mobileSearchInputElem ? 
    mobileSearchInputElem.addEventListener('keydown', function(e) {
      if (e.key === 'Escape') {
        if (mobileSearchContainer) {
          mobileSearchContainer.style.display = 'none';
        }
        
        if (mobileSearchInputElem) {
          mobileSearchInputElem.value = '';
        }

        if (mobileSearchResultsElem) {
          while (mobileSearchResultsElem.firstChild) {
            mobileSearchResultsElem.removeChild(mobileSearchResultsElem.firstChild);
          }
        }
        if (htmlElem) {
          htmlElem.style.overflowY = 'visible';
        }
      }
    }) : null;
  


  
    var localTheme = localStorage.getItem('theme');
    var rootEleme = document.getElementById('root');
    var selectThemeElem = document.querySelectorAll('.select-theme');
    var selectThemeItemElem = document.querySelectorAll('.select-theme__item');
    
    if (localTheme) {
      selectThemeItemElem ? 
      selectThemeItemElem.forEach(function (elem) {
        if (elem.text.trim() === localTheme) {
          elem.classList.add('is-active');
        } else {
          elem.classList.remove('is-active');
        }
      }) : null;
    }

    selectThemeItemElem ? 
    selectThemeItemElem.forEach(function (v, i) {
      v.addEventListener('click', function (e) {
        var selectedThemeVariant = e.target.text.trim();
        localStorage.setItem('theme', selectedThemeVariant);

        rootEleme.removeAttribute('class');
        rootEleme.classList.add(`theme__${selectedThemeVariant}`);
        selectThemeElem.forEach(function(rootElem) {
          rootElem.querySelectorAll('a').forEach(function (elem) {
            if (elem.classList) {
              if (elem.text.trim() === selectedThemeVariant) {
                if (!elem.classList.contains('is-active')) {
                  elem.classList.add('is-active');
                }
              } else {
                if (elem.classList.contains('is-active')) {
                  elem.classList.remove('is-active');
                }
              }
            }
          });
        });

        if (window.mermaid) {
          if (selectedThemeVariant === "dark" || selectedThemeVariant === "hacker") {
            mermaid.initialize({ theme: 'dark' });
            location.reload();
          } else {
            mermaid.initialize({ theme: 'default' });
            location.reload();
          }
        }

        var utterances = document.querySelector('iframe');
        if (utterances) {
          utterances.contentWindow.postMessage({
            type: 'set-theme',
            theme: selectedThemeVariant === "dark" || selectedThemeVariant === "hacker" ? 'photon-dark' : selectedThemeVariant === 'kimbie' ? 'github-dark-orange' : 'github-light',
          }, 'https://utteranc.es');
        }
      });
    }) : null;
  


  
    
    var langprefix = JSON.parse("\"\"");
    var searchResults = null;
    var searchMenu = null;
    var searchText = null;
    
    
    var enableSearchHighlight = JSON.parse("null");
    
    var enableSearch = JSON.parse("true");

    var fuse = null;

    if (enableSearch) {
      (function initFuse() {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', baseurl + langprefix + "/index.json");
        xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
        xhr.onload = function () {
          if (xhr.status === 200) {
            fuse = new Fuse(JSON.parse(xhr.response.toString('utf-8')), {
              keys: ['title', 'description', 'content'],
              includeMatches: enableSearchHighlight,
              shouldSort: true,
              threshold: 0.4,
              location: 0,
              distance: 100,
              maxPatternLength: 32,
              minMatchCharLength: 1,
            });
          }
          else {
            console.error(`[${xhr.status}]Error:`, xhr.statusText);
          }
        };
        xhr.send();
      })();
    }
    
    function makeLi(ulElem, obj) {
      var li = document.createElement('li');
      li.className = 'search-result__item';
      
      var a = document.createElement('a');
      a.innerHTML = obj.title;
      a.setAttribute('class', 'search-result__item--title');
      a.setAttribute('href', obj.permalink);

      var descDiv = document.createElement('div');
      descDiv.setAttribute('class', 'search-result__item--desc');
      if (obj.description) {
        descDiv.innerHTML = obj.description.substring(0, 80);
      } else if (obj.content) {
        descDiv.innerHTML = obj.content.substring(0, 80);
      }
      
      li.appendChild(a);
      li.appendChild(descDiv);
      ulElem.appendChild(li);
    }

    function makeHighlightLi(ulElem, obj) {
      var li = document.createElement('li');
      li.className = 'search-result__item';
      var descDiv = null;

      var a = document.createElement('a');
      a.innerHTML = obj.item.title;
      a.setAttribute('class', 'search-result__item--title');
      a.setAttribute('href', obj.item.uri);

      if (obj.matches && obj.matches.length) {
        for (var i = 0; i < obj.matches.length; i++) {
          if ('title' === obj.matches[i].key) {
            a = document.createElement('a');
            a.innerHTML = generateHighlightedText(obj.matches[i].value, obj.matches[i].indices);
            a.setAttribute('class', 'search-result__item--title');
            a.setAttribute('href', obj.item.uri);
          }
          
          if ('description' === obj.matches[i].key) {
            descDiv = document.createElement('div');
            descDiv.setAttribute('class', 'search-result__item--desc');
            descDiv.innerHTML = generateHighlightedText(obj.item.description, obj.matches[i].indices);
          } else if ('content' === obj.matches[i].key) {
            if (!descDiv) {
              descDiv = document.createElement('div');
              descDiv.setAttribute('class', 'search-result__item--desc');
              descDiv.innerHTML = generateHighlightedText(obj.item.content.substring(0, 80), obj.matches[i].indices);
            }
          } else {
            if (obj.item.description) {
              descDiv = document.createElement('div');
              descDiv.setAttribute('class', 'search-result__item--desc');
              descDiv.innerHTML = obj.item.description;
            } else {
              descDiv = document.createElement('div');
              descDiv.setAttribute('class', 'search-result__item--desc');
              descDiv.innerHTML = obj.item.content.substring(0, 80);
            }
          }
        }

        li.appendChild(a);
        if (descDiv) {
          li.appendChild(descDiv);
        }
        if (li) {
          ulElem.appendChild(li);
        }
      }
    }

    function renderSearchResults(searchText, results) {
      searchResults = document.getElementById('search-results');
      searchMenu = document.getElementById('search-menu');
      searchResults.setAttribute('class', 'dd is-active');
      
      var ul = document.createElement('ul');
      ul.setAttribute('class', 'dd-content search-content');

      if (results.length) {
        results.forEach(function (result) {
          var li = document.createElement('li');
          var a = document.createElement('a');
          a.setAttribute('href', result.uri);
          a.setAttribute('class', 'dd-item');
          a.appendChild(li);

          var titleDiv = document.createElement('div');
          titleDiv.innerHTML = result.title;
          titleDiv.setAttribute('class', 'search-result__item--title');

          var descDiv = document.createElement('div');
          descDiv.setAttribute('class', 'search-result__item--desc');
          if (result.description) {
            descDiv.innerHTML = result.description;
          } else if (result.content) {
            descDiv.innerHTML = result.content.substring(0, 80);
          }

          li.appendChild(titleDiv);
          li.appendChild(descDiv);
          ul.appendChild(a);
        });
      } else {
        var li = document.createElement('li');
        li.setAttribute('class', 'dd-item');
        li.innerText = 'No results found';
        ul.appendChild(li);
      }

      while (searchMenu.hasChildNodes()) {
        searchMenu.removeChild(
          searchMenu.lastChild
        );
      }
      
      searchMenu.appendChild(ul);
    }

    function renderSearchHighlightResults(searchText, results) {
      searchResults = document.getElementById('search-results');
      searchMenu = document.getElementById('search-menu');
      searchResults.setAttribute('class', 'dd is-active');

      var ul = document.createElement('ul');
      ul.setAttribute('class', 'dd-content search-content');

      if (results.length) {
        results.forEach(function (result) {
          var li = document.createElement('li');
          var a = document.createElement('a');
          var descDiv = null;

          a.setAttribute('href', result.item.uri);
          a.setAttribute('class', 'dd-item');
          a.appendChild(li);

          var titleDiv = document.createElement('div');
          titleDiv.innerHTML = result.item.title;
          titleDiv.setAttribute('class', 'search-result__item--title');
          
          if (result.matches && result.matches.length) {
            for (var i = 0; i < result.matches.length; i++) {
              if ('title' === result.matches[i].key) {
                titleDiv.innerHTML = generateHighlightedText(result.matches[i].value, result.matches[i].indices);
              }

              if ('description' === result.matches[i].key) {
                descDiv = document.createElement('div');
                descDiv.setAttribute('class', 'search-result__item--desc');
                descDiv.innerHTML = generateHighlightedText(result.item.description, result.matches[i].indices);
              } else if ('content' === result.matches[i].key) {
                if (!descDiv) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'search-result__item--desc');
                  descDiv.innerHTML = generateHighlightedText(result.item.content.substring(0, 80), result.matches[i].indices);
                }
              } else {
                if (result.item.description) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'search-result__item--desc');
                  descDiv.innerHTML = result.item.description;
                } else {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'search-result__item--desc');
                  descDiv.innerHTML = result.item.content.substring(0, 80);
                }
              }
            }
            
            li.appendChild(titleDiv);
            if (descDiv) {
              li.appendChild(descDiv);
            }
            ul.appendChild(a);
          }
        });
      } else {
        var li = document.createElement('li');
        li.setAttribute('class', 'dd-item');
        li.innerText = 'No results found';
        ul.appendChild(li);
      }

      while (searchMenu.hasChildNodes()) {
        searchMenu.removeChild(
          searchMenu.lastChild
        );
      }
      searchMenu.appendChild(ul);
    }

    function renderSearchResultsMobile(searchText, results) {
      searchResults = document.getElementById('search-mobile-results');

      var content = document.createElement('div');
      content.setAttribute('class', 'mobile-search__content');

      if (results.length > 0) {
        results.forEach(function (result) {
          var item = document.createElement('a');
          item.setAttribute('href', result.uri);
          item.innerHTML = '<div class="mobile-search__item"><div class="mobile-search__item--title">📄 ' +
             result.title + '</div><div class="mobile-search__item--desc">' + 
               (result.description ? result.description.substring(0,40) : result.content.substring(0,40)) +
                '</div></div>';
          content.appendChild(item);
        });
      } else {
        var item = document.createElement('span');
        content.appendChild(item);
      }

      let wrap = document.getElementById('search-mobile-results');
      while (wrap.firstChild) {
        wrap.removeChild(wrap.firstChild)
      }
      searchResults.appendChild(content);      
    }

    function renderSearchHighlightResultsMobile(searchText, results) {
      searchResults = document.getElementById('search-mobile-results');

      var ul = document.createElement('div');
      ul.setAttribute('class', 'mobile-search__content');

      if (results.length) {
        results.forEach(function (result) {
          var li = document.createElement('li');
          var a = document.createElement('a');
          var descDiv = null;

          a.setAttribute('href', result.item.uri);
          a.appendChild(li);
          li.setAttribute('class', 'mobile-search__item');

          var titleDiv = document.createElement('div');
          titleDiv.innerHTML = result.item.title;
          titleDiv.setAttribute('class', 'mobile-search__item--title');
          
          if (result.matches && result.matches.length) {
            for (var i = 0; i < result.matches.length; i++) {
              if ('title' === result.matches[i].key) {
                titleDiv.innerHTML = generateHighlightedText(result.matches[i].value, result.matches[i].indices);
              }

              if ('description' === result.matches[i].key) {
                descDiv = document.createElement('div');
                descDiv.setAttribute('class', 'mobile-search__item--desc');
                descDiv.innerHTML = generateHighlightedText(result.item.description, result.matches[i].indices);
              } else if ('content' === result.matches[i].key) {
                if (!descDiv) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'mobile-search__item--desc');
                  descDiv.innerHTML = generateHighlightedText(result.item.content.substring(0, 150), result.matches[i].indices);
                }
              } else {
                if (result.item.description) {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'mobile-search__item--desc');
                  descDiv.innerHTML = result.item.description;
                } else {
                  descDiv = document.createElement('div');
                  descDiv.setAttribute('class', 'mobile-search__item--desc');
                  descDiv.innerHTML = result.item.content.substring(0, 150);
                }
              }
            }
            
            li.appendChild(titleDiv);
            if (descDiv) {
              li.appendChild(descDiv);
            }
            ul.appendChild(a);
          }
        });
      } else {
        var item = document.createElement('span');
        ul.appendChild(item);
      }

      let wrap = document.getElementById('search-mobile-results');
      while (wrap.firstChild) {
        wrap.removeChild(wrap.firstChild)
      }
      searchResults.appendChild(ul);
    }

    function generateHighlightedText(text, regions) {
      if (!regions) {
        return text;
      }

      var content = '', nextUnhighlightedRegionStartingIndex = 0;

      regions.forEach(function(region) {
        if (region[0] === region[1]) {
          return null;
        }
        
        content += '' +
          text.substring(nextUnhighlightedRegionStartingIndex, region[0]) +
          '<span class="search__highlight">' +
            text.substring(region[0], region[1] + 1) +
          '</span>' +
        '';
        nextUnhighlightedRegionStartingIndex = region[1] + 1;
      });

      content += text.substring(nextUnhighlightedRegionStartingIndex);

      return content;
    };

    var searchElem = document.getElementById('search');
    var searchMobile = document.getElementById('search-mobile');
    var searchResultsContainer = document.getElementById('search-results');

    searchElem ? 
    searchElem.addEventListener('input', function(e) {
      if (!e.target.value | window.innerWidth < 770) {
        searchResultsContainer ? searchResultsContainer.setAttribute('class', 'dd') : null;
        return null;
      }

      searchText = e.target.value;
      var results = fuse.search(e.target.value);

      if (enableSearchHighlight) {
        renderSearchHighlightResults(searchText, results);
      } else {
        renderSearchResults(searchText, results);
      }

      var dropdownItems = searchResultsContainer.querySelectorAll('.dd-item');
      dropdownItems ? dropdownItems.forEach(function (item) {
        item.addEventListener('mousedown', function (e) {
          e.target.click();
        });
      }) : null;
    }) : null;

    searchElem ? 
    searchElem.addEventListener('blur', function() {
      if (window.innerWidth < 770) {
        return null;
      }
      searchResultsContainer ? searchResultsContainer.setAttribute('class', 'dd') : null;
    }) : null;

    searchElem ? 
    searchElem.addEventListener('click', function(e) {
      if (window.innerWidth < 770) {
        return null;
      }
      if (!e.target.value) {
        searchResultsContainer ? searchResultsContainer.setAttribute('class', 'dd') : null;
        return null;
      }

      searchText = e.target.value;
      var results = fuse.search(e.target.value);

      if (enableSearchHighlight) {
        renderSearchHighlightResults(searchText, results);
      } else {
        renderSearchResults(searchText, results);
      }

      var dropdownItems = searchResultsContainer.querySelectorAll('.dd-item');
      dropdownItems ? dropdownItems.forEach(function (item) {
        item.addEventListener('mousedown', function (e) {
          e.target.click();
        });
      }) : null;
    }) : null;

    var searchMenuElem = document.getElementById("search-menu");
    var activeItem = document.querySelector('#search-menu .dd-item.is-active');
    var activeIndex = null;
    var items = null;
    var searchContainerMaxHeight = 350;

    searchElem ? 
    searchElem.addEventListener('keydown', function(e) {
      if (window.innerWidth < 770) {
        return null;
      }

      var items = document.querySelectorAll('#search-menu .dd-item');
      
      if (e.key === 'ArrowDown') {
        if (activeIndex === null) {
          activeIndex = 0;
          items[activeIndex].classList.remove('is-active');
        } else {
          items[activeIndex].classList.remove('is-active');
          activeIndex = activeIndex === items.length - 1 ? 0 : activeIndex + 1;
        }
        items[activeIndex].classList.add('is-active');

        let overflowedPixel = items[activeIndex].offsetTop + items[activeIndex].clientHeight - searchContainerMaxHeight;
        if (overflowedPixel > 0) {
          document.querySelector(".search-content").scrollTop += items[activeIndex].getBoundingClientRect().height;
        } else if (activeIndex === 0) {
          document.querySelector(".search-content").scrollTop = 0;
        }
      } else if (e.key === 'ArrowUp') {
        if (activeIndex === null) {
          activeIndex = items.length - 1;
          items[activeIndex].classList.remove('is-active');
        } else {
          items[activeIndex].classList.remove('is-active');
          activeIndex = activeIndex === 0 ? items.length - 1 : activeIndex - 1;
        }
        items[activeIndex].classList.add('is-active');
        
        let overflowedPixel = items[activeIndex].offsetTop + items[activeIndex].clientHeight - searchContainerMaxHeight;
        if (overflowedPixel < 0) {
          document.querySelector(".search-content").scrollTop -= items[activeIndex].getBoundingClientRect().height;
        } else {
          document.querySelector(".search-content").scrollTop = overflowedPixel + items[activeIndex].getBoundingClientRect().height;
        }
      } else if (e.key === 'Enter') {
        var currentItemLink = items[activeIndex].getAttribute('href');
        if (currentItemLink) {
          location.href = currentItemLink;
        }
      } else if (e.key === 'Escape') {
        e.target.value = null;
        if (searchResults) {
          searchResults.classList.remove('is-active');
        }
      }
    }) : null;

    searchMobile ? 
    searchMobile.addEventListener('input', function(e) {
      if (!e.target.value) {
        let wrap = document.getElementById('search-mobile-results');
        while (wrap.firstChild) {
          wrap.removeChild(wrap.firstChild);
        }
        return null;
      }

      searchText = e.target.value;
      var results = fuse.search(e.target.value);
      
      if (enableSearchHighlight) {
        renderSearchHighlightResultsMobile(searchText, results);
      } else {
        renderSearchResultsMobile(searchText, results);
      }

      var dropdownItems = searchResultsContainer.querySelectorAll('.dd-item');
      dropdownItems ? dropdownItems.forEach(function (item) {
        item.addEventListener('mousedown', function (e) {
          e.target.click();
        });
      }) : null;
    }) : null;
  
  }
</script>
    


<link rel="stylesheet" href="/css/main.min.css">


    <meta name="description" content="" />
<meta name="keywords" content="">
<meta name="created" content="2018-07-22T22:05:32&#43;0800">
<meta name="modified" content="2020-02-28T11:19:00&#43;0800">
<meta name="author" content="邵晨峰">

<meta property="og:site_name" content="邵晨峰的博客">
<meta property="og:title" content="nuklear的设计与源码分析">
<meta property="og:url" content="http://shaochenfeng.com/blog/nuklear%E7%9A%84%E8%AE%BE%E8%AE%A1%E4%B8%8E%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/">
<meta property="og:type" content="article">
<meta property="og:image" content="http://shaochenfeng.com/me/nuklear%E4%BD%9C%E8%80%85.jpg">
<meta name="generator" content="Hugo 0.81.0" />
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="theme-color" content="#ffffff">
<link rel="canonical" href="http://shaochenfeng.com/blog/nuklear%E7%9A%84%E8%AE%BE%E8%AE%A1%E4%B8%8E%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/">
<link rel="manifest" href="/manifest.json">

  <link rel="apple-touch-icon" sizes="57x57" href="/favicon/apple-icon-57x57.png">
  <link rel="apple-touch-icon" sizes="60x60" href="/favicon/apple-icon-60x60.png">
  <link rel="apple-touch-icon" sizes="72x72" href="/favicon/apple-icon-72x72.png">
  <link rel="apple-touch-icon" sizes="76x76" href="/favicon/apple-icon-76x76.png">
  <link rel="apple-touch-icon" sizes="114x114" href="/favicon/apple-icon-114x114.png">
  <link rel="apple-touch-icon" sizes="120x120" href="/favicon/apple-icon-120x120.png">
  <link rel="apple-touch-icon" sizes="144x144" href="/favicon/apple-icon-144x144.png">
  <link rel="apple-touch-icon" sizes="152x152" href="/favicon/apple-icon-152x152.png">
  <link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-icon-180x180.png">
  <link rel="icon" type="image/png" sizes="192x192" href="/favicon/android-icon-192x192.png">
  <link rel="icon" type="image/png" sizes="192x192" href="/favicon/android-icon-512x512.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png">
  <link rel="icon" type="image/png" sizes="96x96" href="/favicon/favicon-96x96.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png">
  <meta name="msapplication-TileColor" content="#ffffff">
  <meta name="msapplication-TileImage" content="/ms-icon-144x144.png">

    <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    "headline": "nuklear的设计与源码分析",
    "datePublished": "2018-07-22T22:05:32+08:00",
    "dateModified": "2020-02-28T11:19:00+08:00",
    "url" : "http://shaochenfeng.com/blog/nuklear%E7%9A%84%E8%AE%BE%E8%AE%A1%E4%B8%8E%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/",
    "description": "\u003ch2 id=\"更新于-2020年2月-源作者已不再维护请谨慎选择\"\u003e更新于 2020年2月 源作者已不再维护，请谨慎选择\u003c/h2\u003e \u003cp\u003e最近在逛Github时发现了一个单文件跨平台零依赖的图形库\u003ca href=\"https://github.com/vurtun/nuklear\" target=\"_blank\"\u003e\u003cstrong\u003enuklear\u003c/strong\u003e\u003c/a\u003e，这使我产生了兴趣，一个大约两万行的程序，实现了很不错的效果，更神奇的是它是零依赖的，这意味着可以运用到类似单片机等特殊环境，于是我果断Fork了它开始了学习之路\u003ca href=\"https://github.com/zoollcar/nuklear\" target=\"_blank\"\u003e\u003cstrong\u003ezoollcar/nuklear\u003c/strong\u003e\u003c/a\u003e，下面我们分析 …\u003c/p\u003e",
    "keywords": ["nuklear"],
    "image" : "http://shaochenfeng.com/me/nuklear%E4%BD%9C%E8%80%85.jpg",
    "author": {
      "@type": "Person",
      "name": "邵晨峰"
    },
    "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": "http://shaochenfeng.com"
    },
    "publisher": {
      "@type": "Organization",
      "name": "邵晨峰的博客",
      "url": "http://shaochenfeng.com"
    }
  }
</script>

    
<script>

var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?bbd1a2ff6319307f954c5233f13dcc26";
  var s = document.getElementsByTagName("script")[0];
  s.parentNode.insertBefore(hm, s);
})();
var _mtac = {};
(function() {
	var mta = document.createElement("script");
	mta.src = "//pingjs.qq.com/h5/stats.js?v2.0.4";
	mta.setAttribute("name", "MTAH5");
	mta.setAttribute("sid", "500711551");
	var s = document.getElementsByTagName("script")[0];
	s.parentNode.insertBefore(mta, s);
})();
(function(){
    var bp = document.createElement('script');
    var curProtocol = window.location.protocol.split(':')[0];
    if (curProtocol === 'https') {
        bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
    }
    else {
        bp.src = 'http://push.zhanzhang.baidu.com/push.js';
    }
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(bp, s);
})();
</script>

</head>


<body id="root" class="theme__light">
    <script>
        var rootElem = document.getElementById('root');
        var themeOptions = JSON.parse("[\"light\",\"dark\"]");
        var localTheme = localStorage.getItem('theme');

        if (localTheme) {
            if (themeOptions && themeOptions.length > 0) {
                themeOptions.includes(localTheme) ? 
                rootElem.className = `theme__${localTheme}` :
                rootElem.className = `theme__${themeOptions[0]}`;
            }
        }
    </script>
    
    <div id="container">
        <div id="myDrawer" class="drawer" style="">
  <div class="drawer__header">
    <a href="/" class="drawer__header--text">
      邵晨峰的博客
    </a>
    <div class="grow"></div>
    <div class="drawer__close">
      <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M18.3 5.71c-.39-.39-1.02-.39-1.41 0L12 10.59 7.11 5.7c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.02 0 1.41L10.59 12 5.7 16.89c-.39.39-.39 1.02 0 1.41.39.39 1.02.39 1.41 0L12 13.41l4.89 4.89c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4z"/></svg>
    </div>
  </div>

  <div class="drawer__body">
    <div class="menu">
  <h6 class="menu__label">
    
    
      nuklear的设计与源码分析
    
  </h6>
  <ul>
    
    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/camunda-springboot%E4%B8%8E%E8%BF%9B%E9%98%B6%E5%86%85%E5%AE%B9/"
      class="menu__title ">Camunda SpringBoot与进阶内容</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/camunda-%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/"
      class="menu__title ">Camunda 快速入门</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/%E6%BA%90%E7%A0%81%E5%AE%89%E8%A3%85%E6%96%B9%E5%BC%8Fcentos7_nginx_php7.3/"
      class="menu__title ">源码安装方式 centos7 nginx php7.3</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/javaexecutor%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%A1%88%E4%BE%8B/"
      class="menu__title ">javaExecutor线程池案例</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/java%E9%81%8D%E5%8E%86%E6%95%B0%E7%BB%84listsetmap%E7%9A%84%E7%A7%8D%E7%A7%8D%E6%96%B9%E6%B3%95/"
      class="menu__title ">Java遍历数组、List、Set、Map的种种方法</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/java%E6%96%87%E4%BB%B6%E7%9A%84%E8%AF%BB%E5%86%99%E9%81%8D%E5%8E%86/"
      class="menu__title ">Java各种文件的读写和文件夹遍历方法</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/vsftpd%E6%90%AD%E5%BB%BAftp/"
      class="menu__title ">vsftpd搭建ftp</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/java-%E8%AF%BB%E5%86%99gbk%E7%BC%96%E7%A0%81%E7%9A%84%E6%96%87%E4%BB%B6/"
      class="menu__title ">Java 读写GBK编码的文件</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/%E7%94%A8%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%9E%84%E5%BB%BA%E8%BF%90%E8%A1%8Cspringboot%E9%A1%B9%E7%9B%AE/"
      class="menu__title ">用命令行构建和运行springboot项目</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/%E5%86%99%E7%BB%99%E5%A4%A7%E5%BF%99%E4%BA%BA%E7%9C%8B%E7%9A%84git%E6%A1%88%E4%BE%8B%E6%80%BB%E7%BB%93/"
      class="menu__title ">写给大忙人看的Git案例总结</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/cento8%E5%AE%89%E8%A3%85szabbix%E7%9B%91%E6%8E%A7/"
      class="menu__title ">Centos8安装zabbix监控，源码方式</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/rpm%E5%B0%81%E8%A3%85%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AArpm%E5%8C%85%E7%9A%84%E7%AE%80%E5%8C%96%E6%8C%87%E5%8D%97/"
      class="menu__title ">RPM封装：创建一个RPM包的简化指南</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/firewall%E5%B8%B8%E7%94%A8%E8%A7%84%E5%88%99%E8%AE%BE%E7%BD%AE/"
      class="menu__title ">Firewall常用规则设置【转发】</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/2020%E5%B9%B4spring%E6%89%80%E6%9C%89%E5%AE%98%E6%96%B9%E9%A1%B9%E7%9B%AE%E4%BB%8B%E7%BB%8D/"
      class="menu__title ">2020年Spring所有官方项目介绍</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/%E5%88%9D%E6%8E%A2%E7%94%A8nginx-rtmp-module%E8%87%AA%E5%BB%BA%E7%9B%B4%E6%92%AD%E6%9C%8D%E5%8A%A1%E5%99%A8/"
      class="menu__title ">初探用nginx Rtmp Module自建直播服务器</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/supervisor-%E5%AE%88%E6%8A%A4%E8%BF%9B%E7%A8%8B%E5%B7%A5%E5%85%B7%E8%BD%AC%E8%BD%BD/"
      class="menu__title ">Supervisor-守护进程工具【转载】</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/apache_httpd%E5%92%8Cphp/"
      class="menu__title ">Apache httpd结合php，yum方式和源码方式</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/centos87%E5%AE%89%E8%A3%85tomcat9%E5%92%8C%E5%B8%B8%E8%A7%81%E7%94%A8%E6%B3%95/"
      class="menu__title ">Centos8(7)安装tomcat9和常见用法</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/yum%E5%AE%89%E8%A3%85httpdapache%E5%B9%B6%E8%AE%BE%E7%BD%AE%E8%99%9A%E6%8B%9F%E4%B8%BB%E6%9C%BA/"
      class="menu__title ">Yum安装httpd(apache)并设置虚拟主机</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/%E6%BA%90%E7%A0%81%E5%AE%89%E8%A3%85nginx%E5%88%B0%E6%8C%87%E5%AE%9A%E7%9B%AE%E5%BD%95/"
      class="menu__title ">源码安装nginx到指定目录</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/nginx%E9%85%8D%E7%BD%AEssl%E8%AF%81%E4%B9%A6%E6%94%AF%E6%8C%81htts/"
      class="menu__title ">Nginx配置ssl证书，支持https</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/yum%E5%AE%89%E8%A3%85mysql5.7%E6%9F%A5%E7%9C%8B%E9%BB%98%E8%AE%A4root%E5%AF%86%E7%A0%81/"
      class="menu__title ">yum安装mysql5.7，查看默认root密码</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/yum%E5%AE%89%E8%A3%85mysql8%E6%9F%A5%E7%9C%8B%E9%BB%98%E8%AE%A4root%E5%AF%86%E7%A0%81/"
      class="menu__title ">yum安装mysql8，查看默认root密码</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/sed%E5%B8%B8%E7%94%A8%E6%A8%A1%E6%9D%BF%E6%95%B4%E7%90%86/"
      class="menu__title ">sed常用模板整理</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/nginx%E7%AB%AF%E5%8F%A3%E8%BD%AC%E5%8F%91%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86/"
      class="menu__title ">Nginx端口转发（反向代理）</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/%E7%94%A8rsync%E5%AE%9E%E7%8E%B0%E7%BD%91%E7%AB%99%E7%9A%84%E5%A2%9E%E9%87%8F%E9%83%A8%E7%BD%B2/"
      class="menu__title ">用Rsync,实现网站的增量部署</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/%E7%BA%A2%E5%B8%BD8%E5%8F%91%E8%A1%8C%E7%89%88%E8%AF%B4%E6%98%8Epdf/"
      class="menu__title ">红帽8发行版说明PDF</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/2020%E5%B9%B4centos87%E6%9B%B4%E6%8D%A2yum%E6%BA%90%E4%B8%BA%E9%98%BF%E9%87%8C%E6%BA%90/"
      class="menu__title ">2020年CentOS8(7)更换yum源为阿里源</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/centos8yum%E5%AE%89%E8%A3%85nginx%E5%B9%B6%E8%AE%BE%E7%BD%AE%E8%99%9A%E6%8B%9F%E4%B8%BB%E6%9C%BA/"
      class="menu__title ">Centos8 Yum安装nginx并设置虚拟主机</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/c%E8%AF%AD%E8%A8%80%E6%A0%87%E5%87%86%E5%BA%93stdlib.h%E5%AD%A6%E4%B9%A0/"
      class="menu__title ">C语言标准库stdlib</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/%E5%85%B3%E4%BA%8E%E6%88%91/"
      class="menu__title ">关于我</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/acme.sh/"
      class="menu__title ">使用acme.sh进行ssl申请和自动续约</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/markdown-syntax/"
      class="menu__title ">Markdown Syntax Guide</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/placeholder-text/"
      class="menu__title ">Placeholder Text</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="">
    <a href="http://shaochenfeng.com/blog/emoji-support/"
      class="menu__title ">Emoji Support</a>
  </li>
  

    
      
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  <li class="active">
    <a href="http://shaochenfeng.com/blog/nuklear%E7%9A%84%E8%AE%BE%E8%AE%A1%E4%B8%8E%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/"
      class="menu__title active">nuklear的设计与源码分析</a>
  </li>
  

    
  </ul>
</div>



<script>
  var menuTitle = document.querySelectorAll('.menu__title');
  var modal = document.getElementById("myModal");
  var drawer = document.getElementById('myDrawer');

  var closeDrawer = function () {
    setTimeout(function () {
      modal.style.opacity = 0;
      drawer.style.left = '-100%';
      modal.style.left = '-100%';
    }, 250);
  }

  menuTitle ? 
  menuTitle.forEach(function(elem) {
    elem.onclick = function() {
      closeDrawer();
      localStorage.setItem('isDrawerOpen', 'false');
    }
  }) : null;
</script>
  </div>
</div>
<div id="myModal" class="modal" style=""></div>

<script>
  var isDrawerOpen = localStorage.getItem('isDrawerOpen');
  var modal = document.getElementById("myModal");
  var drawer = document.getElementById('myDrawer');
  
  
  var languagedir = JSON.parse("\"ltr\"");

  var openDrawer = function () {
    modal.style.opacity = 1;
    
    if (languagedir === "rtl") {
      modal.style.right = 0;
      drawer.style.right = 0;
    } else {
      modal.style.left = 0;
      drawer.style.left = 0;
    }
  }

  if (isDrawerOpen && isDrawerOpen === 'true') {
    openDrawer();
  }
</script>
        
<nav class="nav">
  <div class="navbar__wrapper" data-bgimg="false">
    <div class="divider">
      <div class="navbar lmr">
        <div id="siteLogo" class="navbar__logo--wrapper">
  
    <a href="/" title="" rel="home" class="navbar__logo--link">
      <img src="/logo.png" alt="Home" class="navbar__logo">
    </a>
  
  
    <a href="/" title="" rel="home" class="navbar__logo--text-link">
      <h6 class="navbar__logo--text" data-bgimg="false">邵晨峰的博客</h6>
    </a>
  
</div>
        
        <div class="navbar__menu--wrapper">
          <div id="tabletLogo" class="hide">
  
  <a href="/" rel="home" class="navbar__logo--link">
    <img src="/logo.png" alt="Home" class="navbar__logo">
  </a>
  
</div>
          <div id="mobileLogo" class="hide">
  <a href="#" class="navbar__logo--link">
    <div class="navbar__icons--icon">
      <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M4 18h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1zm0-5h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1zM3 7c0 .55.45 1 1 1h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1z"/></svg>
    </div>
  </a>
</div>
          <span id="navMenuMobile" class="hide">
  <button id="navCollapseBtn" class="navbar__dropdown--title" aria-label="Section Menu" data-dir="ltr">
    
      blog
    
    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"><path fill="currentColor" d="M8.12 9.29L12 13.17l3.88-3.88c.39-.39 1.02-.39 1.41 0 .39.39.39 1.02 0 1.41l-4.59 4.59c-.39.39-1.02.39-1.41 0L6.7 10.7c-.39-.39-.39-1.02 0-1.41.39-.38 1.03-.39 1.42 0z"/></svg>
  </button>
  <div class="navbar__collapse" data-open="false">
  <ul>
    

  
  
  
  
  <li class="navbar__menu--mobile-item active">
    <a href="/blog" class="active">博客</a>
  </li>

  
  
  
  
  <li class="navbar__menu--mobile-item ">
    <a href="/linux" class="">linux运维</a>
  </li>

  
  
  
  
  <li class="navbar__menu--mobile-item ">
    <a href="/camunda" class="">camunda流程引擎</a>
  </li>

  
  
  
  
  <li class="navbar__menu--mobile-item ">
    <a href="/camunda-cn" class="">camunda中文站</a>
  </li>

  </ul>
</div>
</span>
          <ul id="navMenu" class="navbar__menu">
            

  
  
  
  
  <li class="navbar__menu--item active">
    <a href="/blog" data-bgimg="false">博客</a>
  </li>

  
  
  
  
  <li class="navbar__menu--item ">
    <a href="/linux" data-bgimg="false">linux运维</a>
  </li>

  
  
  
  
  <li class="navbar__menu--item ">
    <a href="/camunda" data-bgimg="false">camunda流程引擎</a>
  </li>

  
  
  
  
  <li class="navbar__menu--item ">
    <a href="/camunda-cn" data-bgimg="false">camunda中文站</a>
  </li>

          </ul>
        </div>
        <div class="grow"></div>
        <div id="siteSearch">
          

<div class="search" data-bgimg="false">
  <span class="icon">
    <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M15.5 14h-.79l-.28-.27c1.2-1.4 1.82-3.31 1.48-5.34-.47-2.78-2.79-5-5.59-5.34-4.23-.52-7.79 3.04-7.27 7.27.34 2.8 2.56 5.12 5.34 5.59 2.03.34 3.94-.28 5.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
  </span>
  <input id="search" aria-label="Site Search" class="input" type="text" autocomplete="no" onkeydown="baiduSearch(event);" placeholder="搜索">
  <div id="search-results" class="dropdown">
    <div id="search-menu" class="dropdown-menu">
    </div>
  </div>
</div>



        </div>
        <div id="mobileSearch" class="hide">
          
<div id="mobileSearchBtn" class="mobile-search__btn">
  <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M15.5 14h-.79l-.28-.27c1.2-1.4 1.82-3.31 1.48-5.34-.47-2.78-2.79-5-5.59-5.34-4.23-.52-7.79 3.04-7.27 7.27.34 2.8 2.56 5.12 5.34 5.59 2.03.34 3.94-.28 5.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>
</div>

<div id="search-mobile-container" class="mobile-search hide">
  <div class="mobile-search__top">
    <input id="search-mobile" type="text" aria-label="Mobile Search" placeholder="Search..." class="mobile-search__top--input"/>
    <div id="search-mobile-close" class="mobile-search__top--icon">
      <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><path opacity=".87" fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm3.59-13L12 10.59 8.41 7 7 8.41 10.59 12 7 15.59 8.41 17 12 13.41 15.59 17 17 15.59 13.41 12 17 8.41z"/></svg>
    </div>
  </div>
  <div id="search-mobile-results" class="mobile-search__body">
    
  </div>
</div>

        </div>
        <div class="navbar__icons">
  
  
<button id="toggleToDark" class="navbar__icons--icon" aria-label="Toggle to dark mode">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></svg>
</button>
<button id="toggleToLight" class="navbar__icons--icon" aria-label="Toggle to light mode">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.38 2.019a7.5 7.5 0 1 0 10.6 10.6C21.662 17.854 17.316 22 12.001 22 6.477 22 2 17.523 2 12c0-5.315 4.146-9.661 9.38-9.981z" fill="rgba(255,255,255,1)"/></svg>
</button>
<script>
  var theme = localStorage.getItem('theme');
  var toggleToLightBtn = document.getElementById('toggleToLight');
  var toggleToDarkBtn = document.getElementById('toggleToDark');

  if (theme && theme === 'dark') {
    toggleToLightBtn.className = 'navbar__icons--icon';
    toggleToDarkBtn.className = 'hide';
  } else {
    toggleToLightBtn.className = 'hide';
    toggleToDarkBtn.className = 'navbar__icons--icon';
  }
</script>

  
</div>


      </div>
    </div>
  </div>
</nav>

<script>
  var siteLogo = document.getElementById('siteLogo');
  var tabletLogo = document.getElementById('tabletLogo');
  var mobileLogo = document.getElementById('mobileLogo');
  var navMenu = document.getElementById('navMenu');
  var navMenuMobile = document.getElementById('navMenuMobile');
  var siteSearch = document.getElementById('siteSearch');
  var mobileSearch = document.getElementById('mobileSearch');
  
  enquire.register("screen and (max-width:1280px)", {
    match: function () {
      siteLogo.className = 'navbar__logo--wrapper';
      tabletLogo.className = 'hide';
      mobileLogo.className = 'hide';
      navMenu.className = 'navbar__menu';
      navMenuMobile.className = 'hide';
      siteSearch.className = '';
      mobileSearch.className = 'hide';
    },
    unmatch: function () {
      siteLogo.className = 'navbar__logo--wrapper';
      tabletLogo.className = 'hide';
      mobileLogo.className = 'hide';
      navMenu.className = 'navbar__menu';
      navMenuMobile.className = 'hide';
      siteSearch.className = '';
      mobileSearch.className = 'hide';
    },
  }).register("screen and (max-width:960px)", {
    match: function () {
      siteLogo.className = 'hide';
      tabletLogo.className = '';
      mobileLogo.className = 'hide';
      navMenu.className = 'navbar__menu';
      navMenuMobile.className = 'hide';
      siteSearch.className = 'hide';
      mobileSearch.className = 'navbar__icons--icon';
    },
    unmatch: function () {
      siteLogo.className = 'navbar__logo--wrapper';
      tabletLogo.className = 'hide';
      mobileLogo.className = 'hide';
      navMenu.className = 'navbar__menu';
      navMenuMobile.className = 'hide';
      siteSearch.className = '';
      mobileSearch.className = 'hide';
    },
  }).register("screen and (max-width:600px)", {
    match: function () {
      siteLogo.className = 'hide';
      tabletLogo.className = 'hide';
      mobileLogo.className = '';
      navMenu.className = 'hide';
      navMenuMobile.className = '';
      siteSearch.className = 'hide';
      mobileSearch.className = 'navbar__icons--icon';
    },
    unmatch: function () {
      siteLogo.className = 'hide';
      tabletLogo.className = '';
      mobileLogo.className = 'hide';
      navMenu.className = 'navbar__menu';
      navMenuMobile.className = 'hide';
      siteSearch.className = 'hide';
      mobileSearch.className = 'navbar__icons--icon';
    },
  });
</script>

        
        

<div class="mid">
  <div class="divider">
    
    <nav id="single-menu" class="l" data-dir="ltr">
    </nav>

    <article id="list-main" class="m" data-dir="ltr">
      
      <div class="single" data-display="block">
  
    <div class="single__title">
      nuklear的设计与源码分析
    </div>
    <div class="single__meta">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M4 4H20V8H4z" opacity=".3"/><path d="M6 1H8V5H6zM16 1H18V5H16z"/><path d="M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h14c1.1,0,2-0.9,2-2V5C21,3.9,20.1,3,19,3z M19,19H5V9h14V19z M19,7H5V5h14V7z"/></svg><time title="创建于">2018年7月22日 </time> &nbsp;&nbsp; <svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="currentColor" d="M 9 1 L 9 3 L 15 3 L 15 1 L 9 1 z M 18.958984 2.7929688 L 17.666016 4.3183594 L 20.615234 6.8183594 L 21.908203 5.2929688 L 18.958984 2.7929688 z M 12 4 C 7.0225467 4 3 8.0225467 3 13 C 3 17.977453 7.0225467 22 12 22 C 16.977453 22 21 17.977453 21 13 C 21 8.0225467 16.977453 4 12 4 z M 12 6 C 15.910547 6 19 9.0894533 19 13 C 19 16.910547 15.910547 20 12 20 C 8.0894533 20 5 16.910547 5 13 C 5 9.0894533 8.0894533 6 12 6 z M 11 8 L 11 14 L 13 14 L 13 8 L 11 8 z"/></svg> <span title="阅读时间"> 7 分钟阅读</span> &nbsp;&nbsp; <svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="16" height="16"><path fill="currentColor" d="M 16 5 C 12.144531 5 9 8.144531 9 12 C 9 14.410156 10.230469 16.550781 12.09375 17.8125 C 8.527344 19.34375 6 22.882813 6 27 L 8 27 C 8 22.570313 11.570313 19 16 19 C 20.429688 19 24 22.570313 24 27 L 26 27 C 26 22.882813 23.472656 19.34375 19.90625 17.8125 C 21.769531 16.550781 23 14.410156 23 12 C 23 8.144531 19.855469 5 16 5 Z M 16 7 C 18.773438 7 21 9.226563 21 12 C 21 14.773438 18.773438 17 16 17 C 13.226563 17 11 14.773438 11 12 C 11 9.226563 13.226563 7 16 7 Z"/></svg> <span title="作者：">邵晨峰</span>
    </div>
  
  <article class="single__contents" data-dir="ltr">
    <h1 class="title" style="border-bottom: 1px solid currentColor">nuklear的设计与源码分析</h1>
    <h2 id="更新于-2020年2月-源作者已不再维护请谨慎选择">更新于 2020年2月 源作者已不再维护，请谨慎选择</h2>
<p>最近在逛Github时发现了一个单文件跨平台零依赖的图形库<a href="https://github.com/vurtun/nuklear" target="_blank"><strong>nuklear</strong></a>，这使我产生了兴趣，一个大约两万行的程序，实现了很不错的效果，更神奇的是它是零依赖的，这意味着可以运用到类似单片机等特殊环境，于是我果断Fork了它开始了学习之路<a href="https://github.com/zoollcar/nuklear" target="_blank"><strong>zoollcar/nuklear</strong></a>，下面我们分析下nuklear图形库的源代码</p>
<h1 id="综述">综述</h1>
<p>首先看一下官方提供的demo（win gui版），后面会一部分一部分的分析</p>
<div class="highlight"><pre style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#09f;font-style:italic">/* win32 实现细节*/</span>
<span style="color:#069;font-weight:bold">while</span> (running)
{
    <span style="color:#09f;font-style:italic">/* 输入部分 */</span>
    <span style="color:#09f;font-style:italic">/* win32 实现细节 */</span>
    nk_input_begin(ctx);
    <span style="color:#09f;font-style:italic">/* input 细节 */</span>
    nk_input_end(ctx);

    <span style="color:#09f;font-style:italic">/* GUI 部分 */</span>
    <span style="color:#069;font-weight:bold">if</span> (nk_begin(ctx, <span style="color:#c30">&#34;Demo&#34;</span>, nk_rect(<span style="color:#f60">50</span>, <span style="color:#f60">50</span>, <span style="color:#f60">200</span>, <span style="color:#f60">200</span>),
        NK_WINDOW_BORDER<span style="color:#555">|</span>NK_WINDOW_MOVABLE<span style="color:#555">|</span>NK_WINDOW_SCALABLE<span style="color:#555">|</span>
        NK_WINDOW_CLOSABLE<span style="color:#555">|</span>NK_WINDOW_MINIMIZABLE<span style="color:#555">|</span>NK_WINDOW_TITLE))
    {
        <span style="color:#069;font-weight:bold">enum</span> {EASY, HARD};
        <span style="color:#069;font-weight:bold">static</span> <span style="color:#078;font-weight:bold">int</span> op <span style="color:#555">=</span> EASY;
        <span style="color:#069;font-weight:bold">static</span> <span style="color:#078;font-weight:bold">int</span> property <span style="color:#555">=</span> <span style="color:#f60">20</span>;
        <span style="color:#09f;font-style:italic">/* 固定小部件像素宽度（纵向布局） */</span>
        <span style="color:#09f;font-style:italic">/* 创建小部件之前使用 nk_layout_xxx 来说明后面的小部件布局 */</span>
        nk_layout_row_static(ctx, <span style="color:#f60">30</span><span style="color:#09f;font-style:italic">/* 高度 */</span>, <span style="color:#f60">80</span><span style="color:#09f;font-style:italic">/* 元素宽度 */</span>, <span style="color:#f60">1</span><span style="color:#09f;font-style:italic">/* 个数 */</span>);
        <span style="color:#069;font-weight:bold">if</span> (nk_button_label(ctx, <span style="color:#c30">&#34;button&#34;</span>)){
            <span style="color:#09f;font-style:italic">/* 点击事件 */</span>
            fprintf(stdout, <span style="color:#c30">&#34;button pressed</span><span style="color:#c30;font-weight:bold">\n</span><span style="color:#c30">&#34;</span>);
        }
        <span style="color:#09f;font-style:italic">/* 小部件横向动态布局（默认是纵向） */</span>
        nk_layout_row_dynamic(ctx, <span style="color:#f60">30</span>, <span style="color:#f60">2</span>);
        <span style="color:#069;font-weight:bold">if</span> (nk_option_label(ctx, <span style="color:#c30">&#34;easy&#34;</span>, op <span style="color:#555">==</span> EASY)) op <span style="color:#555">=</span> EASY;
        <span style="color:#069;font-weight:bold">if</span> (nk_option_label(ctx, <span style="color:#c30">&#34;hard&#34;</span>, op <span style="color:#555">==</span> HARD)) op <span style="color:#555">=</span> HARD;

        nk_layout_row_dynamic(ctx, <span style="color:#f60">22</span>, <span style="color:#f60">1</span>);
        nk_property_int(ctx, <span style="color:#c30">&#34;Compression:&#34;</span>, <span style="color:#f60">0</span>, <span style="color:#555">&amp;</span>property, <span style="color:#f60">100</span>, <span style="color:#f60">10</span>, <span style="color:#f60">1</span>);
    }
    nk_end(ctx);
    <span style="color:#09f;font-style:italic">/* 绘制部分 */</span>
    nk_gdi_render(nk_rgb(<span style="color:#f60">30</span>,<span style="color:#f60">30</span>,<span style="color:#f60">30</span>)); <span style="color:#09f;font-style:italic">/* 平台专用渲染 */</span>
}
</code></pre></div><p>这里去除了win32实现细节，因为它本身虽然是跨平台的，但并不是所有部分都跨平台<br />
整个程序可以分为三个输入部分，GUI部分，绘制部分，他们的关系是这样的：</p>
<pre><code class="language-mermaid" data-lang="mermaid">graph TD;
    输入部分--输入信息--&gt;GUI部分;
    GUI部分--绘制命令--&gt;绘制部分;
</code></pre><p>在 nuklear 中一个称为上下文的变量会贯穿整个程序，其类型为nk_context，其中记录了这个程序几乎所有的信息，包括输入结构体、整体样式、个个窗口、渲染命令缓冲区，它起着连接 nuklear 所有部分的功能</p>
<div class="highlight"><pre style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#09f;font-style:italic">/* 上下文 */</span>
<span style="color:#069;font-weight:bold">struct</span> nk_context {
    <span style="color:#069;font-weight:bold">struct</span> nk_input input; <span style="color:#09f;font-style:italic">/* 输入 */</span>
    <span style="color:#069;font-weight:bold">struct</span> nk_style style; <span style="color:#09f;font-style:italic">/* 样式 */</span>
    <span style="color:#069;font-weight:bold">struct</span> nk_buffer memory; <span style="color:#09f;font-style:italic">/* 缓冲区 */</span>
    <span style="color:#069;font-weight:bold">struct</span> nk_clipboard clip;  <span style="color:#09f;font-style:italic">/* 剪切板 */</span>
    nk_flags last_widget_state;  <span style="color:#09f;font-style:italic">/* 最近一个小部件状态 */</span>
    <span style="color:#069;font-weight:bold">enum</span> nk_button_behavior button_behavior; <span style="color:#09f;font-style:italic">/* 按钮行为是默认还是被替换的 */</span>
    <span style="color:#069;font-weight:bold">struct</span> nk_configuration_stacks stacks;
    <span style="color:#078;font-weight:bold">float</span> delta_time_seconds; <span style="color:#09f;font-style:italic">/* 时间（秒） */</span>

    <span style="color:#09f;font-style:italic">/* 其他细节 */</span>

    <span style="color:#09f;font-style:italic">/* 窗口 */</span>
    <span style="color:#078;font-weight:bold">int</span> build;
    <span style="color:#078;font-weight:bold">int</span> use_pool;
    <span style="color:#069;font-weight:bold">struct</span> nk_pool pool;
    <span style="color:#069;font-weight:bold">struct</span> nk_window <span style="color:#555">*</span>begin; <span style="color:#09f;font-style:italic">/* 窗口链表 */</span>
    <span style="color:#069;font-weight:bold">struct</span> nk_window <span style="color:#555">*</span>end;
    <span style="color:#069;font-weight:bold">struct</span> nk_window <span style="color:#555">*</span>active; <span style="color:#09f;font-style:italic">/* 激活窗口 */</span>
    <span style="color:#069;font-weight:bold">struct</span> nk_window <span style="color:#555">*</span>current; <span style="color:#09f;font-style:italic">/* 当前窗口 */</span>
    <span style="color:#069;font-weight:bold">struct</span> nk_page_element <span style="color:#555">*</span>freelist;
    <span style="color:#078;font-weight:bold">unsigned</span> <span style="color:#078;font-weight:bold">int</span> count;
    <span style="color:#078;font-weight:bold">unsigned</span> <span style="color:#078;font-weight:bold">int</span> seq;
};
</code></pre></div><h1 id="输入部分">输入部分</h1>
<p>input API 负责组织一个由当前鼠标、按键和文本输入所组成的输入状态（nk_input结构体）。 nuklear 并没有直接与系统通信，有输入状态都必须由特定于平台的代码提供的。</p>
<p>nk_input_begin 会清空当前的状态，然后就可以使用nk_input_motion、nk_input_key、nk_input_button、nk_input_scroll、nk_input_char 等 这些输入函数将消息提供给nuklear，nuklear会将这些信息记录在nk_input结构体中。nk_input结构体 在 nk_context 主上下文中。</p>
<p>下面是nk_input的数据结构</p>
<div class="highlight"><pre style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#09f;font-style:italic">/* nk_input结构体，分为键盘和鼠标 */</span>
<span style="color:#069;font-weight:bold">struct</span> nk_input {
    <span style="color:#069;font-weight:bold">struct</span> nk_keyboard keyboard;
    <span style="color:#069;font-weight:bold">struct</span> nk_mouse mouse;
};
<span style="color:#09f;font-style:italic">/* 鼠标结构体 */</span>
<span style="color:#069;font-weight:bold">struct</span> nk_mouse {
    <span style="color:#069;font-weight:bold">struct</span> nk_mouse_button buttons[NK_BUTTON_MAX];
    <span style="color:#069;font-weight:bold">struct</span> nk_vec2 pos;
    <span style="color:#069;font-weight:bold">struct</span> nk_vec2 prev;
    <span style="color:#069;font-weight:bold">struct</span> nk_vec2 delta;
    <span style="color:#069;font-weight:bold">struct</span> nk_vec2 scroll_delta;
    <span style="color:#078;font-weight:bold">unsigned</span> <span style="color:#078;font-weight:bold">char</span> grab;
    <span style="color:#078;font-weight:bold">unsigned</span> <span style="color:#078;font-weight:bold">char</span> grabbed;
    <span style="color:#078;font-weight:bold">unsigned</span> <span style="color:#078;font-weight:bold">char</span> ungrab;
};
<span style="color:#09f;font-style:italic">/* 键盘结构体 */</span>
<span style="color:#069;font-weight:bold">struct</span> nk_keyboard {
    <span style="color:#069;font-weight:bold">struct</span> nk_key keys[NK_KEY_MAX];
    <span style="color:#078;font-weight:bold">char</span> text[NK_INPUT_MAX];
    <span style="color:#078;font-weight:bold">int</span> text_len;
};
</code></pre></div><p>最后使用 nk_input_end 结束输入过程，这会固定下输入信息，知道下一帧中执行 nk_input_begin 。</p>
<h1 id="gui部分">GUI部分</h1>
<p>这部分是 nuklear 中最精彩的部分，这部分是跨平台的，它会将这部分中注册的小部件（按钮，单选，文字等）转换为渲染部分需要的简单命令</p>
<p>总的来说，它的作用就是用尽可能简单的命令制作出美观的 UI 。</p>
<p>建立一个新窗口的方法是 使用 nk_begin 它会在上下文中新建一个窗口，然后的操作就都在这个窗口进行了</p>
<p>在向窗口加入小部件前需要先设定布局， nuklear 使用的是基于行的布局，使用 nk_layout_xxx 来为当前行设置布局，后面再加入的小部件就使用这个布局提供的位置和大小了。</p>
<p>放置小部件可以调用 nk_button_xxx 、 nk_option_xxx 等函数创建，他们会使用 nk_widget 从窗口的 layout 中得到下一个小部件的位置大小信息，然后将渲染信息加入到渲染命令缓冲区</p>
<p>最后使用 nk_end 结束建立这个窗口，可以建立下一个窗口了</p>
<p>具体来说， nk_begin 建立了一个新窗口， nk_layout_xxx 设置这个窗口的 layout 属性来控制下面小部件的位置和大小， nk_button 等建立小部件的函数使用从窗口中得到位置大小信息，然后处理加入到缓冲区</p>
<p>下面结合代码看一遍：</p>
<h2 id="新建窗口">新建窗口</h2>
<p>（为了效果进行了削减，突出重点）：</p>
<div class="highlight"><pre style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#09f;font-style:italic">/* 建立一个新窗口，分离的标题和标识符的窗口，允许出现具有相同名称但不同标题的多个窗口  */</span>
NK_API <span style="color:#078;font-weight:bold">int</span>
<span style="color:#c0f">nk_begin_titled</span>(<span style="color:#069;font-weight:bold">struct</span> nk_context <span style="color:#555">*</span>ctx, <span style="color:#069;font-weight:bold">const</span> <span style="color:#078;font-weight:bold">char</span> <span style="color:#555">*</span>name, <span style="color:#069;font-weight:bold">const</span> <span style="color:#078;font-weight:bold">char</span> <span style="color:#555">*</span>title,
    <span style="color:#069;font-weight:bold">struct</span> nk_rect bounds, nk_flags flags)
{
    <span style="color:#069;font-weight:bold">struct</span> nk_window <span style="color:#555">*</span>win;
    <span style="color:#069;font-weight:bold">struct</span> nk_style <span style="color:#555">*</span>style;

    <span style="color:#09f;font-style:italic">/* 此处省略对参数进行可行性检验的代码 */</span>

    <span style="color:#09f;font-style:italic">/* 下面判断这个名字是否已经存在相同的窗口 */</span>
    <span style="color:#09f;font-style:italic">/* 如果有更新窗口，否则新建窗口 */</span>
    style <span style="color:#555">=</span> <span style="color:#555">&amp;</span>ctx<span style="color:#555">-&gt;</span>style;
    title_len <span style="color:#555">=</span> (<span style="color:#078;font-weight:bold">int</span>)nk_strlen(name);
    <span style="color:#09f;font-style:italic">/* 将窗口名字计算为一个哈希值，比较哈希值比字符串比较快 */</span>
    title_hash <span style="color:#555">=</span> nk_murmur_hash(name, (<span style="color:#078;font-weight:bold">int</span>)title_len, NK_WINDOW_TITLE);
    <span style="color:#09f;font-style:italic">/* 寻找窗口，返回值为0表示没找到，返回值为一个nk_window指针说明找到了 */</span>
    win <span style="color:#555">=</span> nk_find_window(ctx, title_hash, name);
    <span style="color:#09f;font-style:italic">/* 下面创建或更新窗口 */</span>
    <span style="color:#069;font-weight:bold">if</span> (<span style="color:#555">!</span>win) {
        <span style="color:#09f;font-style:italic">/* 创建一个新窗口 create new window */</span>
        nk_size name_length <span style="color:#555">=</span> (nk_size)nk_strlen(name);
        win <span style="color:#555">=</span> (<span style="color:#069;font-weight:bold">struct</span> nk_window<span style="color:#555">*</span>)nk_create_window(ctx);
        NK_ASSERT(win);
        <span style="color:#069;font-weight:bold">if</span> (<span style="color:#555">!</span>win) <span style="color:#069;font-weight:bold">return</span> <span style="color:#f60">0</span>;
        <span style="color:#09f;font-style:italic">/* 将窗口添加到 ctx */</span>
        <span style="color:#069;font-weight:bold">if</span> (flags <span style="color:#555">&amp;</span> NK_WINDOW_BACKGROUND)
            nk_insert_window(ctx, win, NK_INSERT_FRONT);<span style="color:#09f;font-style:italic">/* 顶部添加 */</span>
        <span style="color:#069;font-weight:bold">else</span> nk_insert_window(ctx, win, NK_INSERT_BACK);<span style="color:#09f;font-style:italic">/* 尾部添加 */</span>
        <span style="color:#09f;font-style:italic">/* 初始化命令缓冲区 */</span>
        nk_command_buffer_init(<span style="color:#555">&amp;</span>win<span style="color:#555">-&gt;</span>buffer, <span style="color:#555">&amp;</span>ctx<span style="color:#555">-&gt;</span>memory, NK_CLIPPING_ON);
        win<span style="color:#555">-&gt;</span>flags <span style="color:#555">=</span> flags;
        win<span style="color:#555">-&gt;</span>bounds <span style="color:#555">=</span> bounds;
        win<span style="color:#555">-&gt;</span>name <span style="color:#555">=</span> title_hash;
        <span style="color:#09f;font-style:italic">/* 如果窗口名字比最大长度长，会被截断 */</span>
        name_length <span style="color:#555">=</span> NK_MIN(name_length, NK_WINDOW_MAX_NAME<span style="color:#555">-</span><span style="color:#f60">1</span>);
        NK_MEMCPY(win<span style="color:#555">-&gt;</span>name_string, name, name_length);
        win<span style="color:#555">-&gt;</span>name_string[name_length] <span style="color:#555">=</span> <span style="color:#f60">0</span>;
        <span style="color:#09f;font-style:italic">/* 不是弹出式窗口 */</span>
        win<span style="color:#555">-&gt;</span>popup.win <span style="color:#555">=</span> <span style="color:#f60">0</span>;
        <span style="color:#069;font-weight:bold">if</span> (<span style="color:#555">!</span>ctx<span style="color:#555">-&gt;</span>active)
            ctx<span style="color:#555">-&gt;</span>active <span style="color:#555">=</span> win;
    } <span style="color:#069;font-weight:bold">else</span> {
        <span style="color:#09f;font-style:italic">/* 省略更新窗口的代码 */</span>
    }

    <span style="color:#09f;font-style:italic">/* 省略后面会对鼠标点击后窗口的排列进行控制，大致就是点哪个哪个放到窗口链表顶端 */</span>

    win<span style="color:#555">-&gt;</span>layout <span style="color:#555">=</span> (<span style="color:#069;font-weight:bold">struct</span> nk_panel<span style="color:#555">*</span>)nk_create_panel(ctx);
    ctx<span style="color:#555">-&gt;</span>current <span style="color:#555">=</span> win;
    ret <span style="color:#555">=</span> nk_panel_begin(ctx, title, NK_PANEL_WINDOW);
    win<span style="color:#555">-&gt;</span>layout<span style="color:#555">-&gt;</span>offset_x <span style="color:#555">=</span> <span style="color:#555">&amp;</span>win<span style="color:#555">-&gt;</span>scrollbar.x;
    win<span style="color:#555">-&gt;</span>layout<span style="color:#555">-&gt;</span>offset_y <span style="color:#555">=</span> <span style="color:#555">&amp;</span>win<span style="color:#555">-&gt;</span>scrollbar.y;
    <span style="color:#069;font-weight:bold">return</span> ret;
}
</code></pre></div><h2 id="设置布局函数">设置布局函数：</h2>
<div class="highlight"><pre style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c">NK_LIB <span style="color:#078;font-weight:bold">void</span>
<span style="color:#c0f">nk_row_layout</span>(<span style="color:#069;font-weight:bold">struct</span> nk_context <span style="color:#555">*</span>ctx, <span style="color:#069;font-weight:bold">enum</span> nk_layout_format fmt,<span style="color:#09f;font-style:italic">/* fmt 布局类型 */</span>
    <span style="color:#078;font-weight:bold">float</span> height, <span style="color:#078;font-weight:bold">int</span> cols, <span style="color:#078;font-weight:bold">int</span> width)
{
    <span style="color:#09f;font-style:italic">/* 更新当前行并设置当前行的布局 */</span>
    <span style="color:#069;font-weight:bold">struct</span> nk_window <span style="color:#555">*</span>win;
    NK_ASSERT(ctx);
    NK_ASSERT(ctx<span style="color:#555">-&gt;</span>current);
    NK_ASSERT(ctx<span style="color:#555">-&gt;</span>current<span style="color:#555">-&gt;</span>layout);
    <span style="color:#069;font-weight:bold">if</span> (<span style="color:#555">!</span>ctx <span style="color:#555">||</span> <span style="color:#555">!</span>ctx<span style="color:#555">-&gt;</span>current <span style="color:#555">||</span> <span style="color:#555">!</span>ctx<span style="color:#555">-&gt;</span>current<span style="color:#555">-&gt;</span>layout)
        <span style="color:#069;font-weight:bold">return</span>;
    win <span style="color:#555">=</span> ctx<span style="color:#555">-&gt;</span>current;
    <span style="color:#09f;font-style:italic">/* 创建横向 cols 个面板 高度是 height */</span>
    nk_panel_layout(ctx, win, height, cols); <span style="color:#09f;font-style:italic">/* 在下面 */</span>
    <span style="color:#09f;font-style:italic">/* 根据布局类型设置 */</span>
    <span style="color:#069;font-weight:bold">if</span> (fmt <span style="color:#555">==</span> NK_DYNAMIC)
        win<span style="color:#555">-&gt;</span>layout<span style="color:#555">-&gt;</span>row.type <span style="color:#555">=</span> NK_LAYOUT_DYNAMIC_FIXED;<span style="color:#09f;font-style:italic">/* 固定宽度 */</span>
    <span style="color:#069;font-weight:bold">else</span> win<span style="color:#555">-&gt;</span>layout<span style="color:#555">-&gt;</span>row.type <span style="color:#555">=</span> NK_LAYOUT_STATIC_FIXED;<span style="color:#09f;font-style:italic">/* 动态宽度 */</span>

    win<span style="color:#555">-&gt;</span>layout<span style="color:#555">-&gt;</span>row.ratio <span style="color:#555">=</span> <span style="color:#f60">0</span>;
    win<span style="color:#555">-&gt;</span>layout<span style="color:#555">-&gt;</span>row.filled <span style="color:#555">=</span> <span style="color:#f60">0</span>;
    win<span style="color:#555">-&gt;</span>layout<span style="color:#555">-&gt;</span>row.item_offset <span style="color:#555">=</span> <span style="color:#f60">0</span>;
    win<span style="color:#555">-&gt;</span>layout<span style="color:#555">-&gt;</span>row.item_width <span style="color:#555">=</span> (<span style="color:#078;font-weight:bold">float</span>)width;
}

NK_LIB <span style="color:#078;font-weight:bold">void</span>
<span style="color:#c0f">nk_panel_layout</span>(<span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_context <span style="color:#555">*</span>ctx, <span style="color:#069;font-weight:bold">struct</span> nk_window <span style="color:#555">*</span>win,
    <span style="color:#078;font-weight:bold">float</span> height, <span style="color:#078;font-weight:bold">int</span> cols)
{
    <span style="color:#069;font-weight:bold">struct</span> nk_panel <span style="color:#555">*</span>layout;
    <span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_style <span style="color:#555">*</span>style;
    <span style="color:#069;font-weight:bold">struct</span> nk_command_buffer <span style="color:#555">*</span>out;
    <span style="color:#069;font-weight:bold">struct</span> nk_vec2 item_spacing;
    <span style="color:#069;font-weight:bold">struct</span> nk_color color;

    <span style="color:#09f;font-style:italic">/* 省略对参数可行性检验 */</span>

    <span style="color:#09f;font-style:italic">/* 先获得一些预设的配置数据 prefetch some configuration data */</span>
    layout <span style="color:#555">=</span> win<span style="color:#555">-&gt;</span>layout;
    style <span style="color:#555">=</span> <span style="color:#555">&amp;</span>ctx<span style="color:#555">-&gt;</span>style;
    out <span style="color:#555">=</span> <span style="color:#555">&amp;</span>win<span style="color:#555">-&gt;</span>buffer;
    color <span style="color:#555">=</span> style<span style="color:#555">-&gt;</span>window.background;
    item_spacing <span style="color:#555">=</span> style<span style="color:#555">-&gt;</span>window.spacing;

    <span style="color:#09f;font-style:italic">/* 更新当前行并设置当前行布局 update the current row and set the current row layout */</span>
    <span style="color:#09f;font-style:italic">/* 通过前面获得的 layout 指针更改后面的小部件都会使用的 win-&gt;layout */</span>
    layout<span style="color:#555">-&gt;</span>row.index <span style="color:#555">=</span> <span style="color:#f60">0</span>;
    layout<span style="color:#555">-&gt;</span>at_y <span style="color:#555">+=</span> layout<span style="color:#555">-&gt;</span>row.height;
    layout<span style="color:#555">-&gt;</span>row.columns <span style="color:#555">=</span> cols;
    <span style="color:#069;font-weight:bold">if</span> (height <span style="color:#555">==</span> <span style="color:#f60">0.0f</span>)
        layout<span style="color:#555">-&gt;</span>row.height <span style="color:#555">=</span> NK_MAX(height, layout<span style="color:#555">-&gt;</span>row.min_height) <span style="color:#555">+</span> item_spacing.y;
    <span style="color:#069;font-weight:bold">else</span> layout<span style="color:#555">-&gt;</span>row.height <span style="color:#555">=</span> height <span style="color:#555">+</span> item_spacing.y;

    layout<span style="color:#555">-&gt;</span>row.item_offset <span style="color:#555">=</span> <span style="color:#f60">0</span>;
    <span style="color:#069;font-weight:bold">if</span> (layout<span style="color:#555">-&gt;</span>flags <span style="color:#555">&amp;</span> NK_WINDOW_DYNAMIC) {
        <span style="color:#09f;font-style:italic">/* 为动态区域设置背景 draw background for dynamic panels */</span>
        <span style="color:#069;font-weight:bold">struct</span> nk_rect background;
        background.x <span style="color:#555">=</span> win<span style="color:#555">-&gt;</span>bounds.x;
        background.w <span style="color:#555">=</span> win<span style="color:#555">-&gt;</span>bounds.w;
        background.y <span style="color:#555">=</span> layout<span style="color:#555">-&gt;</span>at_y <span style="color:#555">-</span> <span style="color:#f60">1.0f</span>;
        background.h <span style="color:#555">=</span> layout<span style="color:#555">-&gt;</span>row.height <span style="color:#555">+</span> <span style="color:#f60">1.0f</span>;
        nk_fill_rect(out, background, <span style="color:#f60">0</span>, color);
    }
}
</code></pre></div><h2 id="创建小部件">创建小部件：</h2>
<div class="highlight"><pre style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#09f;font-style:italic">/* 创建按钮 */</span>
NK_API <span style="color:#078;font-weight:bold">int</span>
<span style="color:#c0f">nk_button_text_styled</span>(<span style="color:#069;font-weight:bold">struct</span> nk_context <span style="color:#555">*</span>ctx,
    <span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_style_button <span style="color:#555">*</span>style, <span style="color:#069;font-weight:bold">const</span> <span style="color:#078;font-weight:bold">char</span> <span style="color:#555">*</span>title, <span style="color:#078;font-weight:bold">int</span> len)
{
    <span style="color:#069;font-weight:bold">struct</span> nk_window <span style="color:#555">*</span>win;
    <span style="color:#069;font-weight:bold">struct</span> nk_panel <span style="color:#555">*</span>layout;
    <span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_input <span style="color:#555">*</span>in;

    <span style="color:#069;font-weight:bold">struct</span> nk_rect bounds;
    <span style="color:#069;font-weight:bold">enum</span> nk_widget_layout_states state;

    <span style="color:#09f;font-style:italic">/* 省略对参数可行性检验 */</span>

    <span style="color:#09f;font-style:italic">/* 从 nk_context 中得到位置和大小的 nk_rect  */</span>
    win <span style="color:#555">=</span> ctx<span style="color:#555">-&gt;</span>current;
    layout <span style="color:#555">=</span> win<span style="color:#555">-&gt;</span>layout;
    state <span style="color:#555">=</span> nk_widget(<span style="color:#555">&amp;</span>bounds, ctx);

    <span style="color:#069;font-weight:bold">if</span> (<span style="color:#555">!</span>state) <span style="color:#069;font-weight:bold">return</span> <span style="color:#f60">0</span>;
    <span style="color:#09f;font-style:italic">/* 生成按钮 */</span>
    in <span style="color:#555">=</span> (state <span style="color:#555">==</span> NK_WIDGET_ROM <span style="color:#555">||</span> layout<span style="color:#555">-&gt;</span>flags <span style="color:#555">&amp;</span> NK_WINDOW_ROM) <span style="color:#555">?</span> <span style="color:#f60">0</span> <span style="color:#555">:</span> <span style="color:#555">&amp;</span>ctx<span style="color:#555">-&gt;</span>input;
    <span style="color:#069;font-weight:bold">return</span> nk_do_button_text(<span style="color:#555">&amp;</span>ctx<span style="color:#555">-&gt;</span>last_widget_state, <span style="color:#555">&amp;</span>win<span style="color:#555">-&gt;</span>buffer, bounds,
                    title, len, style<span style="color:#555">-&gt;</span>text_alignment, ctx<span style="color:#555">-&gt;</span>button_behavior,
                    style, in, ctx<span style="color:#555">-&gt;</span>style.font);
}
<span style="color:#09f;font-style:italic">/* 生成按钮函数 */</span>
NK_LIB <span style="color:#078;font-weight:bold">int</span>
<span style="color:#c0f">nk_do_button_text</span>(nk_flags <span style="color:#555">*</span>state,
    <span style="color:#069;font-weight:bold">struct</span> nk_command_buffer <span style="color:#555">*</span>out, <span style="color:#069;font-weight:bold">struct</span> nk_rect bounds,
    <span style="color:#069;font-weight:bold">const</span> <span style="color:#078;font-weight:bold">char</span> <span style="color:#555">*</span>string, <span style="color:#078;font-weight:bold">int</span> len, nk_flags align, <span style="color:#069;font-weight:bold">enum</span> nk_button_behavior behavior,
    <span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_style_button <span style="color:#555">*</span>style, <span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_input <span style="color:#555">*</span>in,
    <span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_user_font <span style="color:#555">*</span>font)
{
    <span style="color:#069;font-weight:bold">struct</span> nk_rect content;
    <span style="color:#078;font-weight:bold">int</span> ret <span style="color:#555">=</span> nk_false;

    <span style="color:#09f;font-style:italic">/* 省略对参数可行性检验 */</span>

    <span style="color:#09f;font-style:italic">/* 计算和返回按钮点击事件 */</span>
    <span style="color:#09f;font-style:italic">/* 这里的使用 nk_input 结构中的鼠标点击位置计算是否点击到按钮 */</span>
    <span style="color:#09f;font-style:italic">/* 如果点击到按钮，会返回相应的点击事件，这个时间会一路返回到用户代码中的if判断 */</span>
    ret <span style="color:#555">=</span> nk_do_button(state, out, bounds, style, in, behavior, <span style="color:#555">&amp;</span>content);
    <span style="color:#069;font-weight:bold">if</span> (style<span style="color:#555">-&gt;</span>draw_begin) style<span style="color:#555">-&gt;</span>draw_begin(out, style<span style="color:#555">-&gt;</span>userdata);<span style="color:#09f;font-style:italic">/* 绘制开始的回调 */</span>
    <span style="color:#09f;font-style:italic">/* 绘制按钮，生成按钮文字 */</span>
    nk_draw_button_text(out, <span style="color:#555">&amp;</span>bounds, <span style="color:#555">&amp;</span>content, <span style="color:#555">*</span>state, style, string, len, align, font);
    <span style="color:#069;font-weight:bold">if</span> (style<span style="color:#555">-&gt;</span>draw_end) style<span style="color:#555">-&gt;</span>draw_end(out, style<span style="color:#555">-&gt;</span>userdata);<span style="color:#09f;font-style:italic">/* 绘制完成的回调 */</span>
    <span style="color:#069;font-weight:bold">return</span> ret;
}
<span style="color:#09f;font-style:italic">/* 真正绘制按钮 外观 */</span>
NK_LIB <span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_style_item<span style="color:#555">*</span>
<span style="color:#c0f">nk_draw_button</span>(<span style="color:#069;font-weight:bold">struct</span> nk_command_buffer <span style="color:#555">*</span>out,
    <span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_rect <span style="color:#555">*</span>bounds, nk_flags state,
    <span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_style_button <span style="color:#555">*</span>style)
{
    <span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_style_item <span style="color:#555">*</span>background;
    <span style="color:#069;font-weight:bold">if</span> (state <span style="color:#555">&amp;</span> NK_WIDGET_STATE_HOVER)
        background <span style="color:#555">=</span> <span style="color:#555">&amp;</span>style<span style="color:#555">-&gt;</span>hover;
    <span style="color:#069;font-weight:bold">else</span> <span style="color:#069;font-weight:bold">if</span> (state <span style="color:#555">&amp;</span> NK_WIDGET_STATE_ACTIVED)
        background <span style="color:#555">=</span> <span style="color:#555">&amp;</span>style<span style="color:#555">-&gt;</span>active;
    <span style="color:#069;font-weight:bold">else</span> background <span style="color:#555">=</span> <span style="color:#555">&amp;</span>style<span style="color:#555">-&gt;</span>normal;

    <span style="color:#069;font-weight:bold">if</span> (background<span style="color:#555">-&gt;</span>type <span style="color:#555">==</span> NK_STYLE_ITEM_IMAGE) {
        <span style="color:#09f;font-style:italic">/* 如果是图片背景，就绘制图片 */</span>
        nk_draw_image(out, <span style="color:#555">*</span>bounds, <span style="color:#555">&amp;</span>background<span style="color:#555">-&gt;</span>data.image, nk_white);
    } <span style="color:#069;font-weight:bold">else</span> {
        <span style="color:#09f;font-style:italic">/* 否则绘制矩形 */</span>
        nk_fill_rect(out, <span style="color:#555">*</span>bounds, style<span style="color:#555">-&gt;</span>rounding, background<span style="color:#555">-&gt;</span>data.color);
        nk_stroke_rect(out, <span style="color:#555">*</span>bounds, style<span style="color:#555">-&gt;</span>rounding, style<span style="color:#555">-&gt;</span>border, style<span style="color:#555">-&gt;</span>border_color);
    }
    <span style="color:#069;font-weight:bold">return</span> background;
}
<span style="color:#09f;font-style:italic">/* 绘制矩形 */</span>
NK_API <span style="color:#078;font-weight:bold">void</span>
<span style="color:#c0f">nk_fill_rect</span>(<span style="color:#069;font-weight:bold">struct</span> nk_command_buffer <span style="color:#555">*</span>b, <span style="color:#069;font-weight:bold">struct</span> nk_rect rect,
    <span style="color:#078;font-weight:bold">float</span> rounding, <span style="color:#069;font-weight:bold">struct</span> nk_color c)
{
    <span style="color:#069;font-weight:bold">struct</span> nk_command_rect_filled <span style="color:#555">*</span>cmd;
    <span style="color:#09f;font-style:italic">/* 省略对参数可行性检验 */</span>
    <span style="color:#09f;font-style:italic">/* 将绘制命令放入命令缓冲区中，先放入再设置属性 */</span>
    cmd <span style="color:#555">=</span> (<span style="color:#069;font-weight:bold">struct</span> nk_command_rect_filled<span style="color:#555">*</span>)
        nk_command_buffer_push(b, NK_COMMAND_RECT_FILLED, <span style="color:#069;font-weight:bold">sizeof</span>(<span style="color:#555">*</span>cmd));
    <span style="color:#069;font-weight:bold">if</span> (<span style="color:#555">!</span>cmd) <span style="color:#069;font-weight:bold">return</span>;
    cmd<span style="color:#555">-&gt;</span>rounding <span style="color:#555">=</span> (<span style="color:#078;font-weight:bold">unsigned</span> <span style="color:#078;font-weight:bold">short</span>)rounding;
    cmd<span style="color:#555">-&gt;</span>x <span style="color:#555">=</span> (<span style="color:#078;font-weight:bold">short</span>)rect.x;
    cmd<span style="color:#555">-&gt;</span>y <span style="color:#555">=</span> (<span style="color:#078;font-weight:bold">short</span>)rect.y;
    cmd<span style="color:#555">-&gt;</span>w <span style="color:#555">=</span> (<span style="color:#078;font-weight:bold">unsigned</span> <span style="color:#078;font-weight:bold">short</span>)NK_MAX(<span style="color:#f60">0</span>, rect.w);
    cmd<span style="color:#555">-&gt;</span>h <span style="color:#555">=</span> (<span style="color:#078;font-weight:bold">unsigned</span> <span style="color:#078;font-weight:bold">short</span>)NK_MAX(<span style="color:#f60">0</span>, rect.h);
    cmd<span style="color:#555">-&gt;</span>color <span style="color:#555">=</span> c;
}
<span style="color:#09f;font-style:italic">/* 将命令加入到命令缓冲  所有的绘制命令都用这个 */</span>
NK_LIB <span style="color:#078;font-weight:bold">void</span><span style="color:#555">*</span>
<span style="color:#c0f">nk_command_buffer_push</span>(<span style="color:#069;font-weight:bold">struct</span> nk_command_buffer<span style="color:#555">*</span> b,
    <span style="color:#069;font-weight:bold">enum</span> nk_command_type t, nk_size size)
{
    NK_STORAGE <span style="color:#069;font-weight:bold">const</span> nk_size align <span style="color:#555">=</span> NK_ALIGNOF(<span style="color:#069;font-weight:bold">struct</span> nk_command);
    <span style="color:#069;font-weight:bold">struct</span> nk_command <span style="color:#555">*</span>cmd;
    nk_size alignment;
    <span style="color:#078;font-weight:bold">void</span> <span style="color:#555">*</span>unaligned;
    <span style="color:#078;font-weight:bold">void</span> <span style="color:#555">*</span>memory;

    NK_ASSERT(b);
    NK_ASSERT(b<span style="color:#555">-&gt;</span>base);
    <span style="color:#069;font-weight:bold">if</span> (<span style="color:#555">!</span>b) <span style="color:#069;font-weight:bold">return</span> <span style="color:#f60">0</span>;
    <span style="color:#09f;font-style:italic">/* 新建一块缓冲区区域，用来将命令加入缓冲区 */</span>
    cmd <span style="color:#555">=</span> (<span style="color:#069;font-weight:bold">struct</span> nk_command<span style="color:#555">*</span>)nk_buffer_alloc(b<span style="color:#555">-&gt;</span>base,NK_BUFFER_FRONT,size,align);
    <span style="color:#069;font-weight:bold">if</span> (<span style="color:#555">!</span>cmd) <span style="color:#069;font-weight:bold">return</span> <span style="color:#f60">0</span>;
    <span style="color:#09f;font-style:italic">/* 确保下一命令的偏移量是对齐的 make sure the offset to the next command is aligned */</span>
    b<span style="color:#555">-&gt;</span>last <span style="color:#555">=</span> (nk_size)((nk_byte<span style="color:#555">*</span>)cmd <span style="color:#555">-</span> (nk_byte<span style="color:#555">*</span>)b<span style="color:#555">-&gt;</span>base<span style="color:#555">-&gt;</span>memory.ptr);
    unaligned <span style="color:#555">=</span> (nk_byte<span style="color:#555">*</span>)cmd <span style="color:#555">+</span> size;
    memory <span style="color:#555">=</span> NK_ALIGN_PTR(unaligned, align);
    alignment <span style="color:#555">=</span> (nk_size)((nk_byte<span style="color:#555">*</span>)memory <span style="color:#555">-</span> (nk_byte<span style="color:#555">*</span>)unaligned);
<span style="color:#099">#ifdef NK_ZERO_COMMAND_MEMORY
</span><span style="color:#099"></span>    NK_MEMSET(cmd, <span style="color:#f60">0</span>, size <span style="color:#555">+</span> alignment);
<span style="color:#099">#endif
</span><span style="color:#099"></span>
    cmd<span style="color:#555">-&gt;</span>type <span style="color:#555">=</span> t;
    cmd<span style="color:#555">-&gt;</span>next <span style="color:#555">=</span> b<span style="color:#555">-&gt;</span>base<span style="color:#555">-&gt;</span>allocated <span style="color:#555">+</span> alignment;
<span style="color:#099">#ifdef NK_INCLUDE_COMMAND_USERDATA
</span><span style="color:#099"></span>    cmd<span style="color:#555">-&gt;</span>userdata <span style="color:#555">=</span> b<span style="color:#555">-&gt;</span>userdata;
<span style="color:#099">#endif
</span><span style="color:#099"></span>    b<span style="color:#555">-&gt;</span>end <span style="color:#555">=</span> cmd<span style="color:#555">-&gt;</span>next;
    <span style="color:#09f;font-style:italic">/* 返回建好的新命令指针 */</span>
    <span style="color:#069;font-weight:bold">return</span> cmd;
}
</code></pre></div><h1 id="渲染部分">渲染部分</h1>
<p>这个库被设计为推给后端绘制 所以它不会直接在屏幕上绘制任何图形. 而是绘制形状、小部件等。 这会缓冲进内存并组成命令队列。 每一帧会有一个带有绘制命令的命令缓冲区，提供给后端 这些绘制命令需要用户在他们自己的后端绘制中实现 之后，命令缓冲区会被清除，并且开始启动一个新帧。</p>
<p>后端是用户编写的在自己设备上可以执行 nuklear 需要的最小命令集的一组函数<br />
其中重点在于遍历GUI部分提供的命令队列，然后根据命令类型执行相应操作</p>
<p>下面看一下 nuklear 自带的在win32 GUI上的实现：</p>
<div class="highlight"><pre style="background-color:#f0f3f3;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c">NK_API <span style="color:#078;font-weight:bold">void</span>
<span style="color:#c0f">nk_gdi_render</span>(<span style="color:#069;font-weight:bold">struct</span> nk_color clear)
{
    <span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_command <span style="color:#555">*</span>cmd;

    HDC memory_dc <span style="color:#555">=</span> gdi.memory_dc;
    SelectObject(memory_dc, GetStockObject(DC_PEN));
    SelectObject(memory_dc, GetStockObject(DC_BRUSH));
    nk_gdi_clear(memory_dc, clear);

    nk_foreach(cmd, <span style="color:#555">&amp;</span>gdi.ctx)
    {
        <span style="color:#069;font-weight:bold">switch</span> (cmd<span style="color:#555">-&gt;</span>type) {
        <span style="color:#069;font-weight:bold">case</span> <span style="color:#99f">NK_COMMAND_NOP</span>: <span style="color:#069;font-weight:bold">break</span>;
        <span style="color:#069;font-weight:bold">case</span> <span style="color:#99f">NK_COMMAND_SCISSOR</span>: {
            <span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_command_scissor <span style="color:#555">*</span>s <span style="color:#555">=</span>(<span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_command_scissor<span style="color:#555">*</span>)cmd;
            nk_gdi_scissor(memory_dc, s<span style="color:#555">-&gt;</span>x, s<span style="color:#555">-&gt;</span>y, s<span style="color:#555">-&gt;</span>w, s<span style="color:#555">-&gt;</span>h);
        } <span style="color:#069;font-weight:bold">break</span>;
        <span style="color:#069;font-weight:bold">case</span> <span style="color:#99f">NK_COMMAND_LINE</span>: {
            <span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_command_line <span style="color:#555">*</span>l <span style="color:#555">=</span> (<span style="color:#069;font-weight:bold">const</span> <span style="color:#069;font-weight:bold">struct</span> nk_command_line <span style="color:#555">*</span>)cmd;
            nk_gdi_stroke_line(memory_dc, l<span style="color:#555">-&gt;</span>begin.x, l<span style="color:#555">-&gt;</span>begin.y, l<span style="color:#555">-&gt;</span>end.x,
                l<span style="color:#555">-&gt;</span>end.y, l<span style="color:#555">-&gt;</span>line_thickness, l<span style="color:#555">-&gt;</span>color);
        } <span style="color:#069;font-weight:bold">break</span>;

        <span style="color:#09f;font-style:italic">/* 省略类似的处理 */</span>

    }
    nk_gdi_blit(gdi.window_dc);
    nk_clear(<span style="color:#555">&amp;</span>gdi.ctx);
}
</code></pre></div>
  </article>
</div>
      
<div class="grow"></div>
<nav class="pagination-single">
  
    
      <a href="http://shaochenfeng.com/blog/emoji-support/" title="Emoji Support" class="pagination-single__left">
        <div class="pagination-single__icon">
          <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="currentColor" d="M19 11H7.83l4.88-4.88c.39-.39.39-1.03 0-1.42-.39-.39-1.02-.39-1.41 0l-6.59 6.59c-.39.39-.39 1.02 0 1.41l6.59 6.59c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L7.83 13H19c.55 0 1-.45 1-1s-.45-1-1-1z"/></svg>
        </div>
        <div class="pagination-single__right-title">Emoji Support</div>
      </a>
    
    <div class="grow"></div>
    
  
</nav>


    </article>
    
    <section id="list-side" class="r" data-dir="ltr">
      
        <div class="toc">
  <h6 class="toc__label">目录</h6>
  <div class="toc__body">
    <nav id="TableOfContents">
  <ul>
    <li><a href="#更新于-2020年2月-源作者已不再维护请谨慎选择">更新于 2020年2月 源作者已不再维护，请谨慎选择</a></li>
  </ul>

  <ul>
    <li><a href="#新建窗口">新建窗口</a></li>
    <li><a href="#设置布局函数">设置布局函数：</a></li>
    <li><a href="#创建小部件">创建小部件：</a></li>
  </ul>
</nav>
  </div>
</div>
      
    </section>

  </div>
</div>

<script>
  'use strict';
  
  function wrap(el, wrapper) {
    el.parentNode.insertBefore(wrapper, el);
    wrapper.appendChild(el);
  }

  (function () {
    var singleContentsElem = document.querySelector('.single__contents');
    singleContentsElem ? 
    singleContentsElem.querySelectorAll('pre > code').forEach(function(elem) {
      var dataLang = elem.getAttribute('data-lang');
      var dataLangWrapper = document.createElement('div');
      var code = null;
      var codeTitle = null;

      if (dataLang && dataLang.includes(':')) {
        code = dataLang.split(':')[0];
        codeTitle = dataLang.split(':')[1];

        dataLangWrapper.className = 'language-' + code;
        dataLangWrapper.setAttribute('data-lang', codeTitle);

        elem.className = 'language-' + code;
        elem.setAttribute('data-lang', codeTitle);
        elem.setAttribute('id', codeTitle);
      }

      if (!dataLang || codeTitle) {
        wrap(elem.parentNode, dataLangWrapper);
      }

    }) : null;
  })();
  


  
  
  var dollarCodeElem = document.querySelectorAll('div.language-\\$');
  var gtCodeElem = document.querySelectorAll('div.language-\\>');
  
  dollarCodeElem ?
  dollarCodeElem.forEach(function(elem) {
    var lnts = elem.parentNode.parentNode ? elem.parentNode.parentNode.querySelectorAll('.lnt') : null;
    lnts ? 
    lnts.forEach(function(lnt) {
      lnt.innerHTML = '$<br/>';
    }) : null;
  }) : null;

  gtCodeElem ?
  gtCodeElem.forEach(function(elem) {
    var lnts = elem.parentNode.parentNode ? elem.parentNode.parentNode.querySelectorAll('.lnt') : null;
    lnts ? 
    lnts.forEach(function(lnt) {
      lnt.innerHTML = '><br/>';
    }) : null;
  }) : null;
  
</script>




<script defer src="/js/helper/getParents.min.js"></script>

<script defer src="/js/helper/closest.min.js"></script>

<script defer src="/js/helper/prev.min.js"></script>

<script defer src="/js/helper/prop.min.js"></script>

<script defer src="/js/helper/fadeinout.min.js"></script>












<script>
  document.addEventListener('DOMContentLoaded', function () {
    'use strict';
    
    
    var tables = document.querySelectorAll('.single__contents > table');
    for (let i = 0; i < tables.length; i++) {
      var table = tables[i];
      var wrapper = document.createElement('div');
      wrapper.className = 'table-wrapper';
      table.parentElement.replaceChild(wrapper, table);
      wrapper.appendChild(table);
    }
    


    
    
    
    var lib = JSON.parse("null");

    if (lib && lib.includes('mermaid')) {
      var themeVariant = localStorage.getItem('theme') || 'light';

      if (themeVariant === "dark") {
        mermaid.initialize({ theme: 'dark' });
      } else {
        mermaid.initialize({ theme: 'default' });
      }
      
      var mermaids = [];
      [].push.apply(mermaids, document.getElementsByClassName('language-mermaid'));
      mermaids.forEach(function(elem) {
        var elemParentNode = elem.parentNode;

        if (elemParentNode !== document.body) {
          elemParentNode.parentNode.insertBefore(elem, elemParentNode);
          elemParentNode.parentNode.removeChild(elemParentNode);
        }

        var newElemWrapper = document.createElement('div');
        newElemWrapper.classList.add('mermaid');
        newElemWrapper.innerHTML = elem.innerHTML;
        elem.replaceWith(newElemWrapper);
      });
    }
    
    

    
    if (lib && lib.includes('katex')) {
      var mathElements = document.getElementsByClassName('math');
      var options = {
        delimiters: [
          { left: "$$", right: "$$", display: true },
          { left: "\\[", right: "\\]", display: true },
          { left: "$", right: "$", display: false },
          { left: "\\(", right: "\\)", display: false }
        ],
      };

      renderMathInElement(document.querySelector('.single__contents'), options);
    }
    


    
    if (lib && lib.includes('flowchartjs')) {
      
      var options = JSON.parse("{\"arrow-end\":\"block\",\"element-color\":\"black\",\"fill\":\"white\",\"flowstate\":{\"approved\":{\"fill\":\"#58C4A3\",\"font-size\":12,\"no-text\":\"n/a\",\"yes-text\":\"APPROVED\"},\"current\":{\"fill\":\"yellow\",\"font-color\":\"red\",\"font-weight\":\"bold\"},\"future\":{\"fill\":\"#FFFF99\"},\"invalid\":{\"fill\":\"#444444\"},\"past\":{\"fill\":\"#CCCCCC\",\"font-size\":12},\"rejected\":{\"fill\":\"#C45879\",\"font-size\":12,\"no-text\":\"REJECTED\",\"yes-text\":\"n/a\"},\"request\":{\"fill\":\"blue\"}},\"font-color\":\"black\",\"font-size\":14,\"line-color\":\"black\",\"line-length\":50,\"line-width\":3,\"no-text\":\"no\",\"scale\":1,\"symbols\":{\"end\":{\"class\":\"end-element\"},\"start\":{\"element-color\":\"green\",\"fill\":\"yellow\",\"font-color\":\"red\"}},\"text-margin\":10,\"x\":0,\"y\":0,\"yes-text\":\"yes\"}");
      var jsonContent = null;

      var flowchartPrefix = "language-flowchart";
      var index = 0;
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + flowchartPrefix + "]"), function(x){
          x.style.display = 'none'
          x.parentNode.style.backgroundColor = "transparent"
          jsonContent = x.innerText;

          var node0 = document.createElement('div');
          node0.id = 'flowchart' + index;
          x.parentNode.insertBefore(node0, x);

          var diagram = flowchart.parse(jsonContent);
          diagram.drawSVG("flowchart"+index, options);

          index +=1;
      });      
    }
    


    
    if (lib && lib.includes('chart')) {
      var borderColor = "#666";
      var bgColor = "#ddd";
      var borderWidth = 2;

      Chart.defaults.global.elements.rectangle.borderWidth = borderWidth;
      Chart.defaults.global.elements.rectangle.borderColor = borderColor;
      Chart.defaults.global.elements.rectangle.backgroundColor = bgColor;

      Chart.defaults.global.elements.line.borderWidth = borderWidth;
      Chart.defaults.global.elements.line.borderColor = borderColor;
      Chart.defaults.global.elements.line.backgroundColor = bgColor;

      Chart.defaults.global.elements.point.borderWidth = borderWidth;
      Chart.defaults.global.elements.point.borderColor = borderColor;
      Chart.defaults.global.elements.point.backgroundColor = bgColor;

      var chartPrefix = "language-chart";
      var index = 0;
      var jsonContent = null;

      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + chartPrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        jsonContent = x.innerText;
        var node0 = document.createElement('canvas');
        var source = null;
        node0.height = 200;
        node0.style.height = 200;
        node0.id = 'myChart' + index;
        source = JSON.parse(jsonContent);
        x.parentNode.insertBefore(node0, x);
        var ctx = document.getElementById('myChart' + index).getContext('2d');
        var myChart = new Chart(ctx, source);
        index += 1;
      });            
    }
    


    
    if (lib && lib.includes('viz')) {
      var vizPrefix = "language-viz-";
      Array.prototype.forEach.call(document.querySelectorAll("[class^=" + vizPrefix + "]"), function (x) {
        x.style.display = 'none'
        x.parentNode.style.backgroundColor = "transparent"
        var engine;
        x.getAttribute("class").split(" ").forEach(function (cls) {
          if (cls.startsWith(vizPrefix)) {
            engine = cls.substr(vizPrefix.length);
          }
        });
        var viz = new Viz();
        viz.renderSVGElement(x.innerText, { engine: engine })
          .then(function (element) {
            element.style.width = "100%";
            x.parentNode.insertBefore(element, x);
          })
      });
    }
    
    
  });
</script>

<script>
  var singleMenu = document.getElementById('single-menu');
  var listMain = document.getElementById('list-main');
  var listSide = document.getElementById('list-side');
  var wideViewAsDefault = JSON.parse("null");

  enquire.register("screen and (max-width:1280px)", {
    match: function () {
      if (wideViewAsDefault) {
        singleMenu.className = 'hide';
        listMain.className = 'lm';
        listSide.className = 'r';
      } else {
        singleMenu.className = 'l';
        listMain.className = 'm';
        listSide.className = 'r';
      }
    },
    unmatch: function () {
      if (wideViewAsDefault) {
        singleMenu.className = 'hide';
        listMain.className = 'lm';
        listSide.className = 'r';
      } else {
        singleMenu.className = 'l';
        listMain.className = 'm';
        listSide.className = 'r';
      }
    },
  }).register("screen and (max-width:960px)", {
    match: function () {
      listSide.className = 'r';
      listMain.className = 'lm';
      singleMenu.className = 'hide';
    },
    unmatch: function () {
      if (wideViewAsDefault) {
        singleMenu.className = 'hide';
        listMain.className = 'lm';
        listSide.className = 'r';
      } else {
        singleMenu.className = 'l';
        listMain.className = 'm';
        listSide.className = 'r';
      }
    },
  }).register("screen and (max-width:600px)", {
    match: function () {
      listSide.className = 'hide';
      listMain.className = 'lmr';
      singleMenu.className = 'hide';
    },
    unmatch: function () {
      listSide.className = 'r';
      listMain.className = 'lm';
      singleMenu.className = 'hide';
    },
  });
</script>

        
<div class="bot">
  <footer class="footer">
    <div class="divider">
      <div class="lmr">
        
          <p class="caption">
            <a href="https://beian.miit.gov.cn/" target="_blank">冀ICP备18002899号</a>    ©2021, All Rights Reserved
          </p>
          
        
      </div>
    </div>
  </footer>
</div>

    </div>

</body>

</html>